[OverTheWire] Natas – Level 16

http://natas16.natas.labs.overthewire.org/

For security reasons, we now filter even more on certain characters
Find words containing…

Nhấn View sourcecode:

Thấy quen quen emo_popo_shame

Vì rằng input đã bị escape một số ký tự chủ chốt, ta buộc phải nghĩ cách khác. Cách hay nhất chính là dùng… Google emo_popo_haha

Có những thứ trong cuộc sống mà chúng ta buộc phải chấp nhận một điều, rằng chúng ta chưa có đủ kiến thức để có thể đạt được nó. Chưa đi học, chúng ta không thể hiểu làm sao để giải cái phương trình bậc 2, và thậm chí cũng không biết rằng nó được gọi là phương trình bậc 2, nên không thể tự tìm cách giải quyết. Các bạn hiểu mình đang nói gì không? emo_popo_angry

Sau khi Google, mình biết được một điều rằng ta có thể lồng các câu lệnh con vào làm tham số của một câu lệnh khác, bằng cách sử dụng $(). Ví dụ:

output:

:sure:

Trở lại chức năng tìm kiếm của task này, dễ thấy ta có thể inject các câu lệnh theo ý muốn và dựa vào kết quả trả về để xác định password cho task 17. Nó kiểu như:

  • Nếu ký tự đầu tiên của task17.pw là ‘a’: Tìm kiếm với keyword = ‘a’.
  • Ngược lại: Tìm kiếm với keyword ‘xxx’ (hoặc 1 từ bất kỳ không xuất hiện trong dictionary.txt).

Như thế, nếu có dữ liệu trả về, thì phép thử của chúng ta là đúng, còn ngược lại, phép thử là sai. Tương tự như vậy đối với các ký tự khác.

Tuy nhiên không hiểu sao mình chật vật mãi với đám ifthenfi mà vẫn không xong, nên mình đã Google tiếp và ra một câu lệnh khác, xì tin hơn nhiều:

Xét 2 câu lệnh sau và output của nó:

abcdef

(không trả về gì cả)

Tức là, nếu ta nhập input sau vào box search:

thì sẽ có 2 trường hợp xảy ra:

  1. Có dữ liệu liên quan đến từ Americanism trả về: Như vậy $(grep…) trả về <rỗng>, tức là phép thử của chúng ta (task17.pw bắt đầu bằng a) là sai.
  2. Không có dữ liệu trả về: Như vậy $(grep…) trả về khác <rỗng>, tức là phép thử của chúng ta là đúng, ta tìm được 1 ký tự của pw.

Lặp lại các phép thử như vậy, ta sẽ có đủ 32 ký tự cần tìm.

Code minh họa (không khuyến cáo dùng vì rất chậm):

Kết quả:

8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

→ flag = 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw.

[OverTheWire] Natas – Level 15

http://natas15.natas.labs.overthewire.org/

Nhấn View sourcecode:

Có một điều khác biệt so với task trước, đó là không hề có câu lệnh in ra password cho level tiếp theo. Vậy phải làm sao?

Có một ý tưởng (dự đoán), đó là liệu trong database có username và password cho level 16?

Thử nhập username = natas16:

This user exists.

Ok, vậy gần như chắc chắn password của user này sẽ là thứ ta cần tìm.

Có nhiều cách để dò pw, mà thường cách phổ thông nhất là so sánh từng ký tự của pw (MYSQL cung cấp cho ta hàm ascii()substring() để làm việc này) với các ký tự hợp lệ (trong trường hợp này là a..z, A..Z, 0..9), tức mất tối đa 26 + 26 + 10 = 62 lần thử để tìm ra một ký tự. Độ dài pw là 32, nên số phép thử là khá lớn.

Nếu đi theo tư tưởng của Binary Search, ta chỉ mất khoảng 7 (hay 8 gì đó =.=) lần thử cho 1 ký tự.

Code minh họa như sau (bạn có thể không cần hiểu, vì mình đọc lại cũng không hiểu lắm emo_popo_pudency, nhưng tư tưởng của Binary Search thì thống nhất trên Google rồi, ai cũng có thể tự cài đặt theo ý thích):

Kết quả:

WaIHEacj63wnNIBROHeqi3p9t0m5nhmh

→ flag = WaIHEacj63wnNIBROHeqi3p9t0m5nhmh.

[OverTheWire] Natas – Level 14

http://natas14.natas.labs.overthewire.org/

Nhấn View sourcecode:

Ta thấy ngay được là username và password đều không bị escape. Inject với câu lệnh được dạy trong sách giáo khoa:

username = " OR 1=1#
password = <gì cũng được>

Kết quả:

Successful login! The password for natas15 is AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J

→ flag = AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J.

[OverTheWire] Natas – Level 12

http://natas12.natas.labs.overthewire.org/

Choose a JPEG to upload (max 1KB)…

Xem source:

Đọc hiểu cơ bản, ta thấy quá trình upload ảnh không có gì đặc biệt, quan trọng nhất là ở đường dẫn của file sau khi được upload:

Có những điểm quan trọng như sau:

  • Tên file (không bao gồm phần mở rộng) được tạo ngẫu nhiên.
  • Phần mở rộng lấy từ thuộc tính filename của form upload.
  • Thuộc tính filename có phần mở rộng cố định là .jpg:

Vì mọi thuộc tính của form (name và value) đều có thể thay đổi được, nên ta hoàn toàn có thể upload 1 file .php lên web để thực thi tác vụ mình muốn (code trên server theo như ta thấy thì nó không xử lý định dạng file) emo_popo_smile

Tạo file 12.php có nội dung:

Tại form upload, sửa thuộc tính filename thành *.php:

Chọn file 12.php và tiến hành upload:

The file ... has been uploaded

Nhấn vào link:

jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

→ flag = jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY.

 

[OverTheWire] Natas – Level 11

http://natas11.natas.labs.overthewire.org/

Cookies are protected with XOR encryption

Xem source:

Ok, chúng ta cần có $data[“showpassword”] == “yes”.

Trước đó, $data được lấy giá trị thông qua hàm loadData():

Hiểu tổng quát, $data được lấy từ biến data của cookie (không có thì lấy từ biến mặc định), với các thao tác xử lý lần lượt là:

base64_decode → xor_encrypt → json_decode

Quá trình này dễ thấy là đối xứng với các thao tác trong hàm saveData():

json_encode → xor_encrypt → base64_encode

Do json_encode, json_decode, base64_encode, base64_decode là các hàm có sẵn của PHP, nên cái ta cần bây giờ là hiểu được hàm xor_encrypt.

Nhưng… khoan đã, nãy giờ chúng ta cứ lan man về vấn đề mã hóa cookie, vậy nó có ý nghĩa gì đối với task này? emo_popo_angry

Hãy nhớ lại rằng, chúng ta phải có $data[“showpassword”] == “yes”, nhưng biến showpassword được mặc định là “no” (trong khai báo $defaultdata), còn cái mà chúng ta có thể thay đổi chỉ là mỗi bgcolor. Vậy thì chỉ còn cách đọc hiểu cơ chế xử lý cookie của task, và chỉnh sửa nó thủ công mà thôi.

Trở về với hàm xor_encrypt:

Rất dễ hiểu, là phép XOR với một dãy byte. Và do biến $key đã bị ẩn, nên ta cần tìm nó. Tìm bằng cách nào?

Chúng ta có input, dựa trên $data = $defaultdata. Chúng ta cũng có output, dựa trên giá trị cookie. Tóm tắt lại một chút:

Thực thi câu lệnh PHP sau để tìm được input của hàm xor_encrypt:

{"showpassword":"no","bgcolor":"#ffffff"}

Tương tự như vậy, thực thi câu lệnh PHP sau để xác định output của hàm xor_encrypt:

Ra xấu quá emo_popo_beat_brickThôi kệ nó đi >.<

Như vậy, ta đã có input và ouput. Kết hợp với tính chất kinh điển của phép toán XOR (mà mình đã từng nhắc đến trong một writeup trước đây), chúng ta coi như có đủ dữ kiện cần thiết. Đoạn code dưới đây sẽ cho ta biết các byte lần lượt được dùng để XOR input thành output là gì:

0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
...

Dễ thấy $key = ‘x71x77x38x4a’. Giờ thì ta đã có thể thay đổi giá trị cookie theo ý muốn được rồi emo_popo_beauty

Đoạn code sau sẽ sinh cho ta một cookie với biến data[“showpassword”] = “yes”:

ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK

Thay thế cookie bằng kết quả vừa thu được:

The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

→ flag = EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3.

[OverTheWire] Natas – Level 10

http://natas10.natas.labs.overthewire.org/

For security reasons, we now filter on certain characters
Find words containing…

Tương tự bài 09, nhưng có vẻ như đã escape mất rồi emo_popo_sweat Xem source:

Như vậy các ký tự bị lọc là:

[ ; | & ]

Cũng đâu có sao nhỉ, không có ; thì cũng vẫn được mà emo_popo_haha Inject với input:

'' /etc/natas_webpass/natas11

Kết quả:

/etc/natas_webpass/natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
dictionary.txt:
dictionary.txt:African
dictionary.txt:Africans
dictionary.txt:Allah
dictionary.txt:Allah's
...

→ flag = U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK.

[OverTheWire] Natas – Level 09

http://natas9.natas.labs.overthewire.org/

Find words containing…

Nhấn View sourcecode:

Cú pháp lệnh grep có thể tham khảo tại:

Thông tin được cung cấp từ đầu:

Each level has access to the password of the next level. Your job is to somehow obtain that next password and level up. All passwords are also stored in /etc/natas_webpass/. E.g. the password for natas5 is stored in the file /etc/natas_webpass/natas5 and only readable by natas4 and natas5.

Do biến $key không bị escape, ta có thể inject bằng input sau:

'' /etc/natas_webpass/natas10;

Kết quả:

nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu

→ flag = nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu.

[OverTheWire] Natas – Level 08

http://natas8.natas.labs.overthewire.org/

Input secret…

Xem source:

 

Như vậy là secret của ta sau khi được encode thì phải bằng với một giá trị hardcode có sẵn. Hàm encode:

y = bin2hex(strrev(base64_encode(x)))

Chú ý rằng bin2hex đây là hàm của php, convert một xâu từ ascii sang hex. Tìm x bằng câu lệnh sau (nguyên tắc Đi rẽ trái – Về rẽ phải):

oubWYf2kBq

Submit với secret thu được:

Access granted. The password for natas9 is W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl

→ flag = W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl.

[OverTheWire] Natas – Level 07

http://natas7.natas.labs.overthewire.org/

Xem source:

Với dạng ?page=xxx, có thể nghĩ ngay đến Remote File Inclusion, và gợi ý đề đường dẫn nằm trong source cũng một phần góp thêm lý lẽ cho quan điểm ấy.

Truy cập:

Kết quả:

DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe

→ flag = DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe.

[OverTheWire] Natas – Level 06

http://natas6.natas.labs.overthewire.org/

Input secret…

Nhấn View sourcecode:

Có thể thấy rằng biến $secret được dùng để so sánh, nhưng nó lại không được khai báo trong file index.php. Vậy nó sẽ nằm trong file secret.inc. Truy cập:

Ra trang trắng tinh, xem source:

<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>

Quay lại submit với secret như trên:

Access granted. The password for natas7 is 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9

→ flag = 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9.