2023 12月第4周周报
一、完成事项
- 64位手动脱壳!
- 使用CFF Explorer组织系统ASLR重定位
- 尝试gdb调试,ida远程调试
- 学习特征值主要算法TEA,DRS,MD5
二、未完成事项
三、下周待做事项
四、本周学习的知识
一、读师傅们周报的启发
- Fi1ix: AES和SM4,大小端序的问题,迷宫脚本
- lyp: ida伪代码里的字符串是小端序,shift+E提取地图数据
- lo1see:gmbh和flag的ASCII码值差1
二、UPX手动脱壳(64位)
示例为 [SWPUCTF 2022 新生赛]upx 中的附件(64位,UPX3.96壳),可以用工具脱壳。下面尝试手动脱壳。
XP后的系统都有ASLR(地址空间随机化),导致dump后程序运行出错,因此我们首先用CFF Explorer修改该文件的Nt Header,禁用ASLR在Nt Header下的Optional Header里修改Characteristics,勾选Relocation info srtipped from file。关闭后记得保存。
用x64dbg打开文件,进入系统断点(push rbx)。
按F9到达该断点(这里要按两次,上面还有个别的什么断点)
F7走完push压栈部分
观察到RSP的变化,在其上右键“在内存窗口中转到”
在右下角该地址右键,设置硬件断点
F9运行到断点处,看到下面的jmp大跳应该是入口,设置断点,F9跳过去
F7步入程序
往下翻可以看到提示字符串
这就正式进入了原程序,可以进行dump了
先点“IAT Autosearch”,再点“Get Imports”,在“Imports”中删除掉带有红色叉叉的,再点击“Dump”,之后“Fix Dump”选中之前的Dump文件,修复成功。
p04 副本_dump_SCY.exe 也可以正常运行
拖入IDA中,这里会不报错,Yes不用管它
(由于某种神秘力量?)没有main函数,只能通过字符串来找函数
X键找一下位置
可以看到大致的代码
如果想把字符串展开看,可以(退到IDA View-A中)修改Segment,取消w勾选
修复后
显然sub_140001540是printf函数,脱壳结束
三、GDB调试(pwndbg)
-
打开文件:gdb ./2-simpleCrackme
Text Only |
---|
| `gdb --args ./ping -c 10 127.0.0.1`<br /> file命令
|
-
调试快捷键
- r:启动
- c:继续
- si:单步步入
- ni:单步步过
- finish:执行到当前函数返回
- b:断点
- intfo b(或l):列出所有断点
- del 序号:删除断点
- clear:删除指定位置断点(clear *main)
- 示例:
四、IDA远程调试
- 选择调试器
- 在虚拟机里查看域名,之后要用
- 填写IDA
- 虚拟机启动 ./linux_server64(视位数而定)
- 可以启动调试了
五、特征值算法
TEA
例题:babyre(unsolved)
运行内容:
64位无壳
符号表被藏了,只能通过字符串寻找主函数
从字符串长度判断切入主函数
20行应当是输入部分
24行 sub_140011019 应当是存储Str到一个数组
进26行 sub_14001106E 看一下:
转换为16进制:v3 = 0x90508D47; v3 -= 0x77BF7F99;
应该是TEA加密,倒推得到解密脚本中的 delta=0x90508D47-3340x77BF7F99=
byte_14001E000为密钥:49, 183, 182, 49
27行 sub_140011087 :
是一个拆字节的函数(对于从 a1 中读取的每个32位整数,使用一个内层循环将其拆分为四个字节)
最终存储到byte_14001E218数组内
查一下byte_14001E040应该是密文:
224, 243, 33, 150, 151, 199, 222, 137, 155, 202, 98, 141, 176, 93, 252, 210, 137, 85, 28, 66, 80
六、ISCTF刷题
crackme
有upx壳,但是工具脱壳失败,直接手脱即可
更简单的方法是拖进cmd可以直接运行!??
EasyRe(疑似错题)
64位无壳直接进
可以看出 ]P_ISRF^PCY[I_YWERYC 是最终的密文(20位)
第一个循环:进行逐位异或
第二个循环:将字符串中的B和X换掉,但是IDA默认编译出来的-101-66显然是负数,本不应该输出任何字符,但是在C中却可以运行,分别换成了Y和C
苦思冥想后我发现,256-101-155,155-66=89正好对应Y,电脑自动把-101转换成155进行计算,因为出现了整数溢出,完整的0-256表从后往前溢出,才造成了这样的结果
选中“-101”(一定要包括负号),先转化为16进制,再换成十进制,就会变成155~~(IDA榆木脑袋!)~~
第三个循环:看似是一个字符串逆序,实际上是将前半部分字符串对称到后半部分去,损失了一般的数据。这里好像是编错了,如果真是这样就没法解密。
如果当成是逆序,可以写出解密脚本:
出现了正常的flag,应该是题目出错了。
babyre
pyinstaller打包,用pyinstxtractor.py和在线pyc转py可以得到python源代码:
(pyc魔术头没被抹去,可以直接用babyre.pyc进行转码)
Python |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | import libnum
from Crypto.Util.number import *
flag = 'ISCTF{******************}'
flags = flag.encode()
e = 65537 #rsa加密
p = libnum.generate_prime(1024) #生成两个大素数
q = libnum.generate_prime(1024)
n = p * q
m = bytes_to_long(flags)
c = pow(m, e, n) #m的e次方对n取模 m^e%n=c m^e=k*n+c
output = open('output.txt', 'w')
output.write('p+q =' + str(p + q) + '\n')
output.write('(p+1)*(q+1)=' + str((p + 1) * (q + 1)) + '\n')
output.write('c=' + str(c) + '\n')
output.close()
|
可以看到是一个魔改的rsa
解密脚本如下:
Python |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | #babyre wp
from z3 import *
import libnum
from Crypto.Util.number import *
p,q,c=Ints('p q c')
S = Solver()
S.add(p+q==292884018782106151080211087047278002613718113661882871562870811030932129300110050822187903340426820507419488984883216665816506575312384940488196435920320779296487709207011656728480651848786849994095965852212548311864730225380390740637527033103610408592664948012814290769567441038868614508362013860087396409860)
S.add((p+1)*(q+1)==
21292789073160227295768319780997976991300923684414991432030077313041762314144710093780468352616448047534339208324518089727210764843655182515955359309813600286949887218916518346391288151954579692912105787780604137276300957046899460796651855983154616583709095921532639371311099659697834887064510351319531902433355833604752638757132129136704458119767279776712516825379722837005380965686817229771252693736534397063201880826010273930761767650438638395019411119979149337260776965247144705915951674697425506236801595477159432369862377378306461809669885764689526096087635635247658396780671976617716801660025870405374520076160
)
S.check()
d = S.model()
p = d[p].as_long()
q = d[q].as_long()
e=65537
c=5203005542361323780340103662023144468501161788183930759975924790394097999367062944602228590598053194005601497154183700604614648980958953643596732510635460233363517206803267054976506058495592964781868943617992245808463957957161100800155936109928340808755112091651619258385206684038063600864669934451439637410568700470057362554045334836098013308228518175901113235436257998397401389511926288739759268080251377782356779624616546966237213737535252748926042086203600860251557074440685879354169866206490962331203234019516485700964227924668452181975961352914304357731769081382406940750260817547299552705287482926593175925396
phi = (p-1)*(q-1)
n=p*q
m = pow(c,inverse(e,phi),n)
flags=long_to_bytes(m)
flag=flags.decode('utf-8','ignore')
print(flag)
|
先用Z3强行求出p、q,算出常规rsa中的phi,然后套用公式求出m
注意各类型的转换
easy_z3
明显z3方程求解,求出l再连在一起
Python |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | print("Please input flag:")
flag = input()
if len(flag)!=42:
print("Check your length!")
exit()
l=[]
for i in range(6):
s=""
for j in flag[i*7:i*7+7]:
s+=hex(ord(j))[2:]
l.append(int(s,16))
if (
(593*l[5] + 997*l[0] + 811*l[1] + 258*l[2] + 829*l[3] + 532*l[4])== 0x54eb02012bed42c08 and \
(605*l[4] + 686*l[5] + 328*l[0] + 602*l[1] + 695*l[2] + 576*l[3])== 0x4f039a9f601affc3a and \
(373*l[3] + 512*l[4] + 449*l[5] + 756*l[0] + 448*l[1] + 580*l[2])== 0x442b62c4ad653e7d9 and \
(560*l[2] + 635*l[3] + 422*l[4] + 971*l[5] + 855*l[0] + 597*l[1])== 0x588aabb6a4cb26838 and \
(717*l[1] + 507*l[2] + 388*l[3] + 925*l[4] + 324*l[5] + 524*l[0])== 0x48f8e42ac70c9af91 and \
(312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x4656c19578a6b1170):
print("Good job!")
else:
print("Wrong\nTry again!!!")
exit()
|
解密:
Python |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | from z3 import *
from Crypto.Util.number import *
l = [Int(f'l_{i}') for i in range(6)] #注意定义字符串数组的语法
S = Solver() #创建约束求解器
S.add((593*l[5] + 997*l[0] + 811*l[1] + 258*l[2] + 829*l[3] + 532*l[4])== 0x54eb02012bed42c08) #添加约束条件
S.add((605*l[4] + 686*l[5] + 328*l[0] + 602*l[1] + 695*l[2] + 576*l[3])== 0x4f039a9f601affc3a)
S.add((373*l[3] + 512*l[4] + 449*l[5] + 756*l[0] + 448*l[1] + 580*l[2])== 0x442b62c4ad653e7d9)
S.add((560*l[2] + 635*l[3] + 422*l[4] + 971*l[5] + 855*l[0] + 597*l[1])== 0x588aabb6a4cb26838)
S.add((717*l[1] + 507*l[2] + 388*l[3] + 925*l[4] + 324*l[5] + 524*l[0])== 0x48f8e42ac70c9af91)
S.add((312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x4656c19578a6b1170)
S.check() #检测是否有解
d=S.model() #输出
flag = b'' #字节字符串
for i in range(6):
flag += long_to_bytes(d[l[i]].as_long()) #long转bytes拼接
print(flag)
|
五、本周自己学习过程中遇到的问题和疑问点
(1)z3好像炸不了指数方程
(2)反调试函数具体怎么找
(3)
(4)
六、情感、思考、观点
- 参加了安洵杯,但是水平还太低。。。啥也不会。积累经验努力学习吧
七、在团队的感触和建议