# picoCTF - Medium - Web Exploitation
## Irish-Name-Repo 1
- Đề bài bảo bạn có thể đăng nhập được không, chắc là nhập một đoạn văn bản nào đấy để lấy mật khẩu, hoặc khác.
+ Xem qua `hint 1`: ``There doesn't seem to be many ways to interact with this. I wonder if the users are kept in a database?`` Làm mình chú ý nhất là câu "có được lưu trong cơ sở dữ liệu(`database`) không?"
+ Xem qua `hint 2`: `Try to think about how the website verifies your login.` Xác minh đăng nhập bằng cách so sánh thông tin người dùng nhập vào với dữ liệu trong hệ thống, mình vẫn tiếp tục nghĩ đến `database`.

- Truy cập vào trang web thì chúng ta thấy 3 gạch trang phía bên trên góc trái, ấn vào thì chúng ta thấy 3 mục:
+ `Close Menu`: đóng thanh này lại, không đáng quan tâm lắm.
+ `Admin Login`: sang phần đăng nhập tài khoản mật khẩu, chưa có thông tin gì nên tạm thời để đấy
+ `Support`: phần này nhiều dữ kiện nên mình tiến vào khám phá trước nhé

- Câu đầu: `Hi. I tried adding my favorite Irish person, Conan O'Brien. But I keep getting something called a SQL Error`:
+ Khi người dùng nhập tên `Conan O'Brien`, hệ thống báo lỗi `SQL Error`.
+ Điều này gợi ý rằng: dấu ``'`` trong tên không được xử lý đúng, gây lỗi câu lệnh `SQL`.
+ Khi nhập `O'Brien`, nếu backend viết SQL kiểu này: `= 'O'Brien';`
+ SQL hiểu sai vì dấu ``'`` sau `O` làm ngắt chuỗi sớm. Phần ``Brien'`` phía sau không hợp lệ → SQL bị lỗi cú pháp.
+ Muốn viết ``'`` trong chuỗi SQL, phải viết thành 2 dấu nháy đơn: ``''``: `'O''Brien'`
+ Đây là cú pháp chuẩn để escape dấu ``'`` trong SQL.
+ Câu chuyện ``"Conan O'Brien"`` chỉ là một ví dụ gợi ý rằng hệ thống không xử lý đúng đầu vào
- Các câu tiếp theo cũng không có thông tin gì quan trọng nên chỉ cần chú ý 3 cái tên `Admin, Anna, JimmyMcTrollface` lỡ sau này có cần để đăng nhập.


`LÊN ĐƯỜNG ĐI TÌM KIẾM THÔNG TIN THÔI !!!`
`KÉO ẢNH SANG TRÌNH DUYỆT KHÁC ĐỂ NHÌN RÕ HƠN NHÉ !!!`

- ``💥 SQL Injection``: Khai thác lỗi bằng cách chèn mã độc vào lệnh `SQL`
- ``⚠️ Gốc rễ vấn đề là gì?``
Lỗi `SQL Injection` xảy ra khi một đoạn mã `SQL` được tạo ra từ dữ liệu đầu vào của người dùng, mà không `kiểm tra kỹ` xem đầu vào đó có `an toàn` không.
- ``🛠️ Ví dụ cụ thể``:
+ Giả sử đoạn code phía backend viết như sau:
```json
var statement = "SELECT * FROM users WHERE name = '" + userName + "'";
```
+Mục đích: Lấy thông tin từ bảng users với tên trùng khớp với userName.
+Nhưng nếu kẻ tấn công nhập:
```json
userName = ' OR '1'='1
```
+Thì đoạn SQL cuối cùng sẽ trở thành:
```json
SELECT * FROM users WHERE name = '' OR '1'='1';
```
- ``🧨 Điều gì xảy ra?``
``'1'='1'`` luôn đúng ⇒ Lệnh truy vấn sẽ trả về `tất cả người dùng` thay vì chỉ `1 người` → kẻ tấn công có thể đăng nhập trái phép hoặc `xem toàn bộ thông tin` người dùng.
- ``🧪 Một số kỹ thuật phổ biến``
+Dùng dấu ``--, {, hoặc /*`` để bỏ qua phần còn lại của câu SQL
+Kẻ tấn công có thể nhập:
```json
' OR '1'='1' --
```
+SQL thực thi:
```json
SELECT * FROM users WHERE name = '' OR '1'='1' -- ';
```
+Dấu ``--`` là comment trong SQL ⇒ phần còn lại bị bỏ qua.
+Nghĩa là không còn kiểm tra `password` nữa!

`CHẮC CHẮN KHI ĐỌC PHẦN KẾT LUẬN THÌ AI CŨNG SẼ CÓ PHẦN KHÔNG HIỂU LẮM NÊN MÌNH ĐÃ TÌM KIẾM THÊM THÔNG TIN ĐỂ CÁC BẠN HIỂU RÕ HƠN VỀ BÀI TẬP NÀY NHÉ !!!`

``📌 Tóm tắt lỗi``:
Loại lỗi: `SQL Injection`
Dạng cụ thể: `Authentication Bypass`
Kỹ thuật: Dùng dấu ``'`` để thoát khỏi chuỗi SQL và ``--`` để comment phần sau
## Irish-Name-Repo 2

- `Tên giống bài trước, có thể là bản nâng cấp hơn của nó vì lượt solves ít hơn 25% so với bài trước`
- ``🔍 Bước 1: Quan sát giao diện ban đầu``
+ Trang này có vẻ giống `Irish-Name-Repo 1`:
+ Có nút 3 gạch mở `menu`
+ Có các mục `Admin Login`, `Support` giống y hệt
+ Có thể vẫn sử dụng `SQL` ở `backend` → khả năng cao vẫn là `SQL Injection`, nhưng sẽ tinh vi hơn (có thể có `filter` hoặc chuẩn bị kỹ hơn).
- ``👨💻 BƯỚC 2: Thử SQL Injection ở phần "Admin Login"``
+ ✏️ Mình nhập thử: `Username: ' OR 1=1 --`
+ Bạn sẽ nhận được thông báo “`SQLi detected`”
+ Đây là dấu hiệu rõ ràng rằng server có cơ chế phát hiện `SQL Injection`, có thể là:
+Tự viết tay một hàm kiểm tra các ký tự nguy hiểm ``(, ', --, OR)``
+Hoặc dùng một công cụ bảo vệ như `WAF` (Web Application Firewall)
- Đến đây thì cũng hơi bí rồi nhưng nhận ra bài trước mình làm được là do dựa vào phần support để lấy thông tin, nên bài này mình cũng sẽ làm như vậy. Quay trở lại bài trước để xem chúng ta đã note những gì nhé:

- `Admin`, `Anna`, `JimmyMcTrollface`: Đây có thể là tên người dùng hợp lệ trong hệ thống.
- Những tên người dùng này có thể liên quan đến các tài khoản đăng nhập hợp lệ hoặc có quyền truy cập đặc biệt trong ứng dụng.
- Ở phần ``Username:``, mình thử bằng cách ghi tên người dùng trước sau đó đến dấu `'` để đóng chuỗi và cuối cùng là dấu `--` để vô hiệu hóa password.
- Ví dụ: ``Anna' --``. Làm và thử với các cái tên còn lại. Nếu không được thì các chữ cái đầu của các tên chúng ta viết thường và thử lại lần nữa.

- Sau khoảng 5, 6 lần thử thì mình đã thành công và tìm hiểu thì thấy việc dùng admin để đăng nhập xảy ra rất nhiều, thậm chí những vụ chấn động cũng có. Mình đã lọc ra các sự kiện đáng chú ý và các tên đăng nhập phổ biến để các bạn tìm hiểu thêm.

## Irish-Name-Repo 3

- "`Seems like the password is encrypted`": Gợi ý này rất quan trọng, vì nó cho biết mật khẩu có thể không được lưu trữ dưới dạng văn bản rõ ràng mà có thể đã được mã hóa. Điều này có thể có nghĩa là bạn cần tìm cách giải mã mật khẩu hoặc tìm cách kiểm tra mật khẩu sau khi mã hóa.
- `Mô tả bài toán`:
+ Mục tiêu: Truy cập vào một trang web bảo mật và thử đăng nhập như `admin`.
+ Trang web này yêu cầu đăng nhập và bạn phải tìm cách đăng nhập dưới tư cách `admin`.
- Các bước đầu tiên như các bài trước, nhập thử mật khẩu của bài 1 và bài 2 xem như nào -> không thành công. Phần `login` của trang web bây giờ chỉ còn phần `password` và không còn phần `username` nữa. Xem qua phần `support` cũng không có thêm thông tin gì, bây giờ mình quay trở lại đọc phần `hints` của đề bài.

- Nhập thử một mật khẩu gì đó, vì là ``type="password"`` nên nó sẽ hiện ``⬤⬤⬤⬤``, vậy nên mình vào `page source` bằng `F12` chỉnh sửa thành ``type="text"`` để hiện rõ phần mật khẩu.
- Mật khẩu không bị thay đổi-mã hóa như phần `hints` của đề bài nói. Vì đã ở trong `source` rồi thì mình cũng nên tìm hiểu và đọc qua vậy.

- Phía dưới phần `password` chúng ta vừa thử thì mình thấy một dòng có ``type="hidden"`` nên cũng tò mò (`hidden=ẩn giấu`). Mình thử lấy từ '`appear`' là trái nghĩa với '`hidden`' để thay vào thì xuất hiện một ô nhập gì đấy và hiện sẵn trong đấy là số `0`. Thật ra khi thử thay bằng chữ gì thì nó cùng đều hiện ra ô đấy, cái này thì mình sẽ tìm hiểu sau.
- `Search google` tìm thông tin về việc này thì mình không thu được kết quả khả quan cho lắm nên mình ném hẳn dòng code ấy vào trong `chat gpt` để tìm hiểu.

- Bước đầu mình cần phải hiểu về `debug`, `value` ở đây nghĩa là gì. Sau khi đọc xong, mình chú ý đến các câu:
+ ``Ở đây là "0", thường được hiểu là tắt hoặc false.``
+ ``In ra thông tin nội bộ (biến, trạng thái, cấu trúc dữ liệu,...).``
- Đọc câu đầu thì mình nghĩ là nếu 0 được hiểu là `tắt hoặc false` thì các số khác ngoài 0 sẽ là `bật hoặc true` à.
- Câu thứ 2 mình nghĩ việc `debug` không in ra thông tin nội bộ có phải là do bị `value` "kìm hãm" không.
- Để giải đáp thắc mắc của bản thân thì mình thử ghi số 1 vào ô điền và vẫn `password` cũ "`dola`" thì nó hiện ra thông báo mới:
```json
password: dola
SQL query: SELECT * FROM admin where password = 'qbyn'
```
- Ngoài ra mình thử nhập 2, 3, 4, 5,... và kể cả số âm thì kết quả vẫn xuất hiện thông báo ấy.
- Chưa kịp làm tiếp bởi vì mình vẫn còn nhiều thắc mắc. Tiếp theo mình nhận ra '`appear`' mình thay cho '`hidden`' thật ra không phải giá trị hợp lệ, chỉ vì mình viết sai kiểu `input` nên nó mới hiển thị ô nhập văn bản thôi.
- Và số `0` hiện trên ô nhập văn bản chính là giá trị `value` của `input` đó, cái này thật ra cũng có thể biết rồi nhưng mình hỏi lại cho chắc chắn.
- Dù gì cũng có thông báo quan trọng rồi, nhìn vào là biết `password` "`dola`" đã bị mã hóa nên mình tìm hiểu thêm `debug` thực sự làm được gì trên `CTF`. Đọc thêm nhiều nguồn tài liệu nữa thì mình thấy hầu như mọi người đều dùng ``value="1"``, vậy mình nhập các số khác `1` vẫn thành công thì nguyên nhân là do đâu:
+ Trường hợp 1: Server chỉ cần debug != 0
+ Trường hợp 2: Server chuyển debug sang số (ép kiểu)
+ Trường hợp 3: Có bảng ánh xạ riêng .....

- Quay trở lại phần đăng nhập, mình chọn bừa mật khẩu `abcdefgh` và value="`270806`" (miễn không phải số 0 là được). Lúc này thông báo sẽ là:
```json
password: abcdefgh
SQL query: SELECT * FROM admin where password = 'nopqrstu'
```
- Đây là lúc chúng ta giải mã để xem đây là loại mã hóa nào. Trước khi tìm hiểu và tự giải mã, mình đã vào phần `bandit` trong trang của mình (đã public nên các bạn có thể vào tham khảo) vì ở đây mình đã giải rất nhiều bài mã hóa. Rất nhanh mình đã phát hiện đây là loại mã hóa tên là `ROT13`, tiếp theo mình sẽ thử mã hóa 2 mật khẩu ở bài trước và đăng nhập thử xem sao nhé.
- Nếu ai hỏi tại sao mình toàn lấy mật khẩu bài trước test cho bài sau thì bởi vì cả 3 bài đều tên là `Irish-Name-Repo` nên mình nghĩ lỗi và cấu trúc của nó cũng same same nhau, chỉ là qua từng level 1, 2, 3 thì nó khó dần lên thôi. Một phần cũng vì đề bài bảo là `Hãy thử xem bạn có thể đăng nhập với tư cách quản trị viên không!`

- Ý đề bài ở đây là ví dụ mật khẩu ban đầu là `abc`, nhưng phải nhập `xyz` mới mở được (dùng bộ mã hóa nào đấy biến `abc` -> `xyz`). Vậy nên phải nhập mật khẩu sau khi mã hóa mới thành công đăng nhập được. Mình đã thử nhập `nqzva' --` rồi nhưng không thành công nhưng khi nhập ``' BE '1'='1`` thì cuối cùng cũng thành công và lấy được cờ.
- Bài học bảo mật rút ra:
+ Không bao giờ tin dữ liệu từ `client` - ô ``<input hidden>`` hay `query‑string` đều có thể bị chỉnh.
+ `Debug mode` phải cấu hình từ `server`, không qua tham số người dùng.
+ Trước khi triển khai, tắt toàn bộ `logging` chi tiết và ẩn thông tin nhạy cảm.
## picobrowser

- Sửa phần User Agent thành picobrowser là được bởi vì khi vào trang web và nhấn nút lấy flag, có dòng xuất hiện là : `You're not picobrowser! Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36`. Sửa lại đúng với những gì nó muốn là được.

## Client-side-again

- Có một đoạn mã Javascript nhìn khá lộn xộn hoặc đã bị mã hóa: `
var _0x5a46=['0a029}','_again_5','this','Password\x20Verified','Incorrect\x20password','getElementById','value','substring','picoCTF{','not_this'];(function(_0x4bd822,_0x2bd6f7){var _0xb4bdb3=function(_0x1d68f6){while(--_0x1d68f6){_0x4bd822['push'](_0x4bd822['shift']());}};_0xb4bdb3(++_0x2bd6f7);}(_0x5a46,0x1b3));var _0x4b5b=function(_0x2d8f05,_0x4b81bb){_0x2d8f05=_0x2d8f05-.....`. Sau khi tìm hiểu thì mình có tìm được một số web gỡ rối đoạn mã này, nó không phải bị mã hóa như tôi nghĩ: https://vietrick.com/apps/js-decrypt/ ; https://beautifier.io/ ...
- Sau khi hoàn thành, tôi chú ý đến các đoạn mã như : ``_0x4b5b('0x0')`` ; ``_0x4b5b('0x1')`` ; ... Lọc ra các đoạn như vậy để giải mã bọn chúng cùng một lúc. Bên cạnh đó tôi có tìm được các công năng của phần `Console` để giải mã mà không cần sự trợ giúp của các web bên ngoài, và nó chỉ hoạt động với `js` thôi. Các đoạn mã đều có form như này :`_0x4b5b('0x..')`, từ x0 đến x9. Tôi nghĩ giải mã xong thì sẽ sắp xếp theo thứ tự này.

## Some Assembly Required 1

- Tương tự như bài `Client-side-again` trên cũng có 1 file js viết lộn xộn, đưa lên web và gỡ rối nó ra gọn gàng dễ nhìn. Nhưng đến khi giải mã thì không có cái nào chứa nội dung của flag.
- Cuối cùng tôi ngồi đọc kỹ từ đầu và chú ý những dòng đầu tiên có mảng `_0x402c` chứa các tên hàm, các biến gì đấy... Có một đường dẫn tệp tên là: `./JIFxzHyW8W` nằm trong mảng đấy, thử thay vào sau url trong file js hiện đang mở thì flag sẽ xuất hiện.

## Power Cookie

- Thay đổi giá trị value từ 0 thành 1 thì xuất hiện flag.
- Trong lập trình, `0` thường đại diện cho giá trị "`sai`" (false) và `1` đại diện cho giá trị "`đúng`" (true) vì đây là một quy ước phổ biến dựa trên `hệ nhị phân` và cách các ngôn ngữ lập trình xử lý các giá trị `boolean` (logic).
## Forbidden Paths

``''Chúng tôi biết các tệp của trang web nằm trong /usr/share/nginx/html/và cờ nằm ở đó, /flag.txt nhưng trang web đang lọc các đường dẫn tệp tuyệt đối. Bạn có thể vượt qua bộ lọc để đọc cờ không?''``
- Thử các file cho sẵn trong web không nhận được nội dung nào quan trọng đến flag, nhập bừa thì báo là file không tồn tại và nhập file flag.txt thì bảo là không được ủy quyền. Theo thông tin đề ra ta biết trang web đang lọc các đường dẫn tệp tuyệt đối.
- Tôi khai thác ``/usr/share/nginx/html/`` bằng cách lùi các cấp thư mục như ``../, ../../, ../../../,``... (lùi 1,2,3 bậc ...). Lùi đến khi nào đọc được file flag thì dừng. Đáp án là: `../../../flag.txt`
## Roboto Sans

- Từ tên bài có nhắc đến robot và đề bài nói rằng flag không nằm trên trang web này, tôi nghĩ đến ngay robots.txt.
- Sau khi truy cập tôi thấy 3 dòng chuỗi gì đấy bị mã hóa, giải mã tất cả không ra gì hết nhưng giải mã từng dòng cho đến dòng 2 thì được 1 chuỗi có nghĩa : `js/myfile.txt`
- Tiếp tục thay nó vào url thì flag xuất hiện :fire:
## Secrets

- Source code page đầu có 1 file ẩn tên là `secret`, truy cập bằng cách thay vào url như thế này : `http://saturn.picoctf.net:56906/secret/`.
- Nó đưa mình sang 1 page khác, tiếp tục truy cập source code thì tìm được 1 file ẩn tên là `hidden`. Thêm vào đằng sau url nhưng vẫn giữ nguyên `secret`.
- Theo cách cũ, tìm được 1 file ẩn tên là `superhidden`, sang page mới cuối cùng cũng có nội dung của flag.
## findme

- Đăng nhập bằng tài khoản mật khẩu hiện có, nó chuyển tôi sang 1 web mới nhưng không có gì khai thác, mặc dù đã cố dùng cách ../ đối với 1 file css lạ ở source code. Hết cách tôi gửi lên burp suite để xem request trả về gì.
- Xem response của phần đăng nhập đầu tiên (POST), nó trả về một đoạn đáng chú ý như sau:

- Thử decode đoạn id thì nó ra phần đầu của flag, cộng thêm trước đó có chữ `next page`, tôi đem đoạn link này quay trở về ban đầu phần đăng nhập và dán nó vào phần GET để xem có trả về nội dung nào quan trọng không. Cuối cùng nó cũng trả về đoạn sau của flag, decode ra và ghép 2 đoạn lại thành 1 flag hoàn chỉnh.

## SQLiLite

- Một bài SQL Injection đơn giản, chỉ cần nhập payload vào là được, ưu tiên các payload có dấu ' vì truy vấn sql của web dùng dấu ' (nhập sai xem thử cấu trúc của nó như thế nào để dễ tìm payload hơn). [Link](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/Intruder/Auth_Bypass.txt)
## Who are you?

- Một bài khá nặng về kiến thức và khả năng tìm tòi, đầu tiên vừa vào web thì có câu : `Only people who use the official PicoBrowser are allowed on this site!`. Thế là tôi vào `Network conditions` chỉnh sửa `user agent` thành `PicoBrowser` sau đó load lại web.
- Tiếp theo có câu `I don't trust users visiting from another site.`, tôi vào ngay `burp suite` để chỉnh sửa thêm phía dưới phần user agent : `Referer: http://mercury.picoctf.net:36622/` (đây là web chính của bài làm). Nội dung header này cho server biết nguồn (`origin/page`) mà request được khởi tạo.
- Tiếp theo có câu `Sorry, this site only worked in 2018.`. Thêm tiếp vào phía dưới: `Date: Tue, 29 Oct 2018 16:56:32 GMT`. Ngày tháng giờ giấc không quan trọng, chỉ cần đổi năm sang 2018 là được. Còn ai tò mò về form thì tìm hiểu ở đây [Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Date)
- Tiếp theo có câu `I don't trust users who can be tracked.` Vậy thì chỉ cần thêm vào `DNT: 1` (do not track), giá trị 1 là `bật` không theo dõi, còn giá trị 0 là `tắt` không theo dõi.
- Tiếp theo có câu `This website is only for people from Sweden.`. Thêm `X-Forwarded-For: 101.157.212.233`. Theo lý thuyết thì dãy số kia phải là ip address của Thụy Điển, nhưng tôi nhập bừa một dãy số thì vẫn đúng, miễn là theo form 4 số thập phân từ `0-255`, ngăn cách nhau bởi dấu chấm, ví dụ `x.x.x.x` [Link](https://lite.ip2location.com/sweden-ip-address-ranges)
- Tiếp theo có câu `You're in Sweden but you don't speak Swedish?`. Thay `Accept-Language: sv-SE,sv;q=0.9`. Cái này thì tìm hiểu trên mạng hoặc là hỏi chat gpt cho nhanh. Cuối cùng là ra nội dung của flag: `What can I say except, you are welcome` `picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_0da16bb2}`

## It is my Birthday

`I sent out 2 invitations to all of my friends for my birthday! I'll know if they get stolen because the two invites look similar, and they even have the same md5 hash, but they are slightly different! You wouldn't believe how long it took me to find a collision. Anyway, see if you're invited by submitting 2 PDFs to my website.`
- Phân tích đề bài và từ quan trọng : `same md5 hash`, `find a collision`, `2 PDFs`. `MD5` viết tắt của Message-Digest Algorithm 5 — là một hàm băm (hash function) được tạo ra để `chuyển đổi dữ liệu` (chuỗi, tệp, mật khẩu, v.v.) thành một chuỗi ký tự cố định dài `32 ký tự` (128 bit). `Collision` (va chạm) xảy ra khi hai dữ liệu khác nhau tạo ra cùng một giá trị băm (`hash`). Nói cách khác: `A ≠ B` nhưng ``MD5(A) = MD5(B)``
- Ví dụ minh họa:
```yaml
Dữ liệu 1: "apple"
→ MD5: 1f3870be274f6c49b3e31a0c6728957f
Dữ liệu 2: "orange"
→ MD5: 1f3870be274f6c49b3e31a0c6728957f ← trùng nhau
```
- Vì sao `collision nguy hiểm`
Vì hash thường được dùng để:
- Xác minh tính toàn vẹn file (file không bị thay đổi),
- Lưu mật khẩu, hoặc
- Xác thực chữ ký số, chứng chỉ, phần mềm tải về.
- Nếu kẻ tấn công tạo được `2 file khác nhau` nhưng `cùng MD5`, hắn có thể `thay thế file thật` `bằng file độc hại` mà hệ thống không phát hiện ra.
- Hãy tưởng tượng hash là “`dấu vân tay`” của dữ liệu.
`Collision` có nghĩa là `hai người khác nhau` có `cùng dấu vân tay` → bạn không thể biết ai thật, ai giả.

- Thử đi tìm demo thì tìm được 1 web này [Link](https://www.mathstat.dal.ca/~selinger/md5collision/). Tải xuống 2 file cùng MD5 và gửi vào bài làm, nó báo : `Not a PDF!`. Vậy thì chỉ cần đổi đuôi của 2 file vừa tải về là `.pdf` là được, bạn nhận về flag.
## caas

- Trang web đưa cho ta 1 đường link `https://caas.mars.picoctf.net/cowsay/{message}` như này mà khi thay vào phần `{message}` 1 câu gì đó ví dụ `hello` thì nó sẽ trả về:
```
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
- Sẽ không có gì ở trong `source code` nhưng bên cạnh đó người ta cho mình 1 `file index.js` như hình trên, truy cập và mở nó ra:
```js
const express = require('express');
const app = express();
const { exec } = require('child_process');
app.use(express.static('public'));
app.get('/cowsay/:message', (req, res) => {
exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => {
if (error) return res.status(500).end();
res.type('txt').send(stdout).end();
});
});
app.listen(3000, () => {
console.log('listening');
});
```
- Vì ``exec()`` gửi chuỗi cho `shell`, nếu input chứa `metacharacter shell` (ví dụ ``;, |, &, $(, backtick, v.v.``) thì shell sẽ phân tích và có thể thực thi lệnh phụ thêm — đó là `command injection`.
- Vào PayloadsAllTheThings để kiếm lệnh thực thi được ([Link](https://github.com/swisskyrepo/PayloadsAllTheThings)). Rất nhanh mình đã tìm ra `a;id;`, nó vẫn sẽ trả về a và phía dưới còn thực thi được lệnh id. Tiếp tục mình thay lệnh id bằng lệnh ls, tìm được file `falg.txt`. Cuối cùng chỉ cần thực thi lệnh cat thì nội dung flag sẽ trả về.

## More Cookies
- Đổi name thành admin và nhận về một đoạn mã, có dấu = ở cuối nên dễ là base64, tôi đã thử decode nhưng không được. Thử thêm rot decode và các loại khác cũng không được.
- Tiếp theo sau khi không ra kết quả, tôi nghĩ về phương án mã bị decode 2, 3 lần thậm chí hơn. Đọc lại đề bài tôi thấy có những từ in hoa vô lý: I forgot `C`ookies can `B`e modified `C`lient-side, so now I decided to encrypt them!
- Thử ghép lại là CBC, tìm hiểu về nó thì đúng là có liên quan, nó là Cipher Block Chaining, thường là AES‑CBC. Nhưng vì không có key nên tạm quên đi việc AES decode, tìm hiểu sâu lại vào CBC vì đây là manh mối duy nhất hiện tại.
- Bước 1: cho là mã gốc ban đầu là base64, decode nó ra 1 lần và giữ nguyên. Đoạn mã mình vừa decode ra có 128 bytes, mà AES xử lý dữ liệu dưới dạng một mảng 16 byte (4×4), chia ra được 8 block.
```
B0: 33 57 56 58 42 31 69 77 63 51 41 54 53 67 50 62
B1: 37 34 37 55 69 6C 76 43 56 58 55 35 43 42 36 49
B2: 72 53 61 50 4D 62 4C 72 65 75 4F 6B 77 54 50 4F
B3: 77 61 64 74 4F 63 34 73 32 6A 34 78 39 6F 79 6C
B4: 52 68 37 45 4F 51 55 6F 43 48 72 6A 4E 49 59 53
B5: 70 58 46 48 47 48 6F 4A 4A 6A 4B 7A 6C 7A 64 65
B6: 78 46 63 67 42 58 53 37 4D 51 65 54 53 4C 77 56
B7: 4B 64 33 36 31 66 52 4E 7A 53 31 38 6C 58 6E 71
```
- Mỗi dòng ở trên là 1 block, B0 là block khởi tạo, không chứa dữ liệu người dùng, chỉ để XOR với Block 1 khi giải mã, tiếp với công thức B1 có công thức là : `P1 = AES_decrypt(Block1, key) XOR Block0` , tiếp tục với B2, B3... (``Pₙ = AES_decrypt(Cₙ) XOR Cₙ₋₁
``). Tìm hiểu thêm ở đây nếu chưa rõ: [Link](https://codelearn.io/sharing/tat-tan-tat-ve-block-cipher?srsltid=AfmBOoo5ylkDEcUQPchJP8ZMZLdn9do0UO4IfA-6KpEMzAXujfLwwoyf)
################`BÀI NÀY CHƯA XONG`################
## MatchTheRegex

- Phân tích phần quan trọng trong source code:
```js
function send_request() {
let val = document.getElementById("name").value;
// ^p.....F!?
fetch(`/flag?input=${val}`)
.then(res => res.text())
.then(res => {
const res_json = JSON.parse(res);
alert(res_json.flag)
return false;
})
return false;
}
```
- `^p.....F!?` :
- ``^`` là ký tự bắt đầu của chuỗi nhập. Ví dụ: ``^A`` nghĩa là A phải là ký tự đầu tiên trong chuỗi, ở đây là `p`.
- `.` là đại diện cho bất kỳ ký tự nào (trừ ký tự xuống dòng), có thể là abcde, 12345, kkkkk, 66666, ...
- Tiếp theo là đến chữ `F` và tiếp đó là `!?` (có thể có ! hoặc không). Không có dấu `$` để kết thúc chuỗi nhập vậy nên bạn thêm gì nữa ở sau chuỗi cũng không sao.
- Các chuỗi trong các trường hợp mà tôi đề cập : `pABCDEF!`, `pABCDEF`, `p12345F!hello`, `p12345Fhello`...
- Có nhiều chuỗi khác nữa sẽ được tạo ra từ Regex trên, bạn nên tìm hiểu các cú pháp của nó để hiểu thêm.