第十二届全国大学生信息安全竞赛 WriteUp
your_pwn
在函数sub_B35
里面,没有对index(v1)
进行检查,从而造成任意地址泄露和任意地址更改。直接改返回地址为one_gadget
即可
1 | for ( i = 0; i <= 40; ++i ) |
详细脚本如下:
1 | from pwn import * |
daily
由于是%s打印内容,会一直打印遇到\x00才会停止,而且add的时候通过read读入没有写入字符串后缀,所以可以利用这一点可以泄露libc地址 和heap地址。泄露利用如下:
1 | create(0x60,"a"*0x20)#0 |
然后利用free的时候没有检查index(v1),漏洞点如下程序部分代码,造成UAF分配到bss上的chunk_list ,然后改free就可以了。
1 | printf("Please enter the index of daily:"); |
然后利用Double free
得到bss
段上的chunk_list
,然后控制chunk
,实现任意地址写,然后我们写free_hook
地址为system
,再free
的时候就可以getshell
了。在这之前,我们尝试了申请到malloc_hook
前面然后把malloc_hoook
覆盖为one_gadget
,但是没有一个one_gadget
可以成功,主要是因为条件没有满足,后来就直接写free_hook
了。
详细脚本如下:
1 | from pwn import * |
最后成功getshell
babypwn
直接read读入0x100直接造成栈溢出,但是这题的难点在于没有泄露函数,不能直接return to libc,所以这里利用ret2_dl_runtime_resolve,之前做过0ctf2018的babystack跟这个类似,先是尝试了roputils库实现,后来发现有点问题总是调不对,后来直接手工干了一波。操作如下:
1 | # -*- coding:utf-8 -*- |
double

由于这个对比,只要输入的data相同则不会分配堆块给data,造成两个指针指向同一个data.
只要申请两个相同内容大小为smallbin,free掉一个指针,show另一个指针即可获得libc的地址
同理只要free掉其中一个,在对另一个相同指向的指针进行edit,就可以改变fd.
将fd改成malloc_hook,再将malloc_hook的值改成one_gadget即可getshell_
详细脚本如下:
1 | from pwn import * |
bms
详细看我另外一篇blog:https://zoepla.github.io/2019/04/csicn2019国赛-bms/
详细脚本如下:
环境:ubuntu18.04 libc2.27
1 | from pwn import * |
usbasp
打开文件后再analyzer里 选SPI,设置选项里最下面选择enable line is active hight

得到下面信息
1 | Time [s],Packet ID,MOSI,MISO |
saleae

同高为1不同为0
然后得到下列数据:
1 | 01100110 |
写个脚本
1 | f = open('data.txt','r') |
justSoso
通过文件包含拿到hint.php和index.php的源码
1 | <html> |
parse_url存在绕过的漏洞,例如:http://127.0.0.1///index.php
构造payload
1 |
|
1 | Payload |
还要把红色位置的1改为2,不然会跳进Waking up函数
1 | O%3A6%3A%22Handle%22%3A2%3A%7Bs%3A14%3A%22%00Handle%00handle%22%3BO%3A4%3A%22Flag%22%3A3%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A10%3A%22token_flag%22%3BN%3Bs%3A5%3A%22token%22%3BR%3A4%3B%7D%7D |

puzzle
question 0
a1,a2,a3,a4

1 | a1:0xfa6 |
part1
看到这三个数都是素数,猜想part1也可能是素数。google到如下的素数表

猜测part1所在位置,根据素数之间的间隔相等的原则,猜出part1为26365399


脚本也可解:
1 | import sympy as sy |


question 3 : 0x48d0


336pi*120/pi=40320
part 4 =hex(40320)=0x9d80
最后得到flag值:FLAG{01924dd7-1e14-48d0-9d80-fa6bed9c7a00}
warmup
本题是AES_CTR加密,而这个加密方式就是分组对明文进行异或,因为在同一次通信中其中的key和计数器不变,所以明文异或的密钥不会变,因此我们可以在通信过程可以通过输入不同的填充获得密钥。
经过测试可以发现,32个一个分组,flag有两个分组多一些,可以先填充5个让flag加填充满足有3*32
个,得到第一个需要的密文data1,然后填充5+48获得第二个密文,第二个密文(data2)有6*32个bit。
则详细脚本如下:
1 | data1 = "aefdd88c71194ba242a1e45c7a03f1e8715e11c3566607ee614c8cd4541f3688f0e5a35146b5cca393c8432dafdccee7" |
Asymmetric
- 看了一下题目给的脚本,其实就是普通的RSA题
- 主要还是把n分解

- 剩下就很简单了

EasyGo
- 查看可执行文件格式
- 程序为Go语言编写,内部函数较为复杂,直接IDA动态调试
定位到sub_495150函数,执行完sub_4886B0,程序打印了字符串 - 在sub_48EB00中,程序调用了输入函数,继续执行,发现函数将一串字符串地址放到了rax
并在接下来的几个CALL中,对其进行了一些操作,这里没有仔细跟进,由于在sub_47E620函数处存在跳转,猜测这里可能为相关的check函数,重点关注其所对应的内存区域,可发现,执行完sub_47E620函数后,可以在内存中直接拿到flag

wp Author
Team233成员