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节 在RMCP+ Open Session Request、RMCP+ Open Session Response的两个包中确定了整个过程中使用的完整性、保密性、认证算法,两个消息的这三个Payload格式是一致的,每个8字节共24字节位于数据的最末端。...

Nov. 15, 2021 · 5 min · 984 words

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; } ?...

Oct. 10, 2021 · 6 min · 1268 words

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....

Oct. 13, 2020 · 15 min · 3015 words

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

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....

Jul. 1, 2020 · 3 min · 514 words

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

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....

May. 23, 2020 · 4 min · 851 words

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