攻防世界逆向高手题之zorropub
2021/9/26 23:14:41
本文主要是介绍攻防世界逆向高手题之zorropub,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
攻防世界逆向高手题之zorropub
继续开启全栈梦想之逆向之旅~
这题是攻防世界逆向高手题的zorropub
.
.
最近有点偷懒了,几天没写题了,时间都是挤出来的,再忙也应该每天抽出时间来做题保持积累才对。
.
.
下载附件,照例扔入exeinfope
中查看信息:
.
.
64
位ELF
文件无壳,kali
上运行不了,可是由于我的linux
只有kali
,所以只能结合别人的资料来分析了。照例扔入IDA64
中查看伪代码,有main
函数看main
函数:
v15 = __readfsqword(0x28u); seed = 0; puts("Welcome to Pub Zorro!!"); printf("Straight to the point. How many drinks you want?"); __isoc99_scanf("%d", &v5); if ( v5 <= 0 ) { printf("You are too drunk!! Get Out!!"); exit(-1); } printf("OK. I need details of all the drinks. Give me %d drink ids:", (unsigned int)v5); for ( i = 0; i < v5; ++i ) { __isoc99_scanf("%d", &v6); if ( v6 <= 16 || v6 > 65535 ) { puts("Invalid Drink Id."); printf("Get Out!!"); exit(-1); } seed ^= v6; } i = seed; v9 = 0; while ( i ) { ++v9; i &= i - 1; } if ( v9 != 10 ) { puts("Looks like its a dangerous combination of drinks right there."); puts("Get Out, you will get yourself killed"); exit(-1); } srand(seed); MD5_Init(v10); for ( i = 0; i <= 29; ++i ) { v9 = rand() % 1000; sprintf(s, "%d", v9); v3 = strlen(s); MD5_Update(v10, s, v3); v12[i] = v9 ^ LOBYTE(qword_6020C0[i]); } v12[i] = 0; MD5_Final(v11, v10); for ( i = 0; i <= 15; ++i ) sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]); if ( strcmp(s1, "5eba99aff105c9ff6a1a913e343fec67") ) { puts("Try different mix, This mix is too sloppy"); exit(-1); } return printf("\nYou choose right mix and here is your reward: The flag is nullcon{%s}\n", v12); }
.
.
先分析代码前半部分,输入的v5
决定了v6
的数量,但是v6
又是用于生成seed
的,所以v5
和v6
其实可以联系在一起,都是用于生成seed
的。
然后生成的seed
又要满足条件才可以作为srand
的随机数种子,所以这里是一个限制条件。
.
.
(这里积累第一个经验)
然后分析后半部分,这里先补充一些函数和以前积累的知识:
(以前积累的知识)
这里也是犯下的第二个错误,以前就听过rand是伪随机数,要用srand
生成随机数种子才行,不然产生的随机数列表都是一样的,而单独产生的随机数也不会在随机数列表用随意取值,而是固定的
第一次这个值,第二次那个值。所以这里我们可以直接修改源代码调试,打印出first_letter的值。
函数积累:
int MD5_Init(MD5_CTX *c)
函数:
初始化 MD5 Contex, 成功返回1,失败返回0
.
int MD5_Update(MD5_CTX *c, const void *data, size_t len)
函数:
循环调用此函数,可以将不同的数据加在一起计算MD5,成功返回1,失败返回
.
int MD5_Final(unsigned char *md, MD5_CTX *c)
函数:
输出MD5结果数据,成功返回1,失败返回0
.
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)
函数:
MD5_Init,MD5_Update,MD5_Final三个函数的组合,直接计算出MD5的值
.
void MD5_Transform(MD5_CTX *c, const unsigned char *b)
函数:
内部函数,不需要调用
其它积累:
%02x
x 表示以十六
进制形式输出
02
表示不足两位
,,前面补0
输出,如果超过
两位,则以实际输出。
sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]);
的意思是把相当于char的__int8的两位输出到&s1[2*i]中,也就是一次输出两个__int8(char)类型的v11[i]到s1的偶数
地址中,所以相当于一个个
赋值而已。
v9
是用特定seed
随机数种子生成的特定的列表,v12
就是flag
。黄框就是特定的v9
列表不断拼凑出的md5加密列表,只要v9
md5
加密后等于5eba99aff105c9ff6a1a913e343fec67
,那么v9
与LOBYTE(qword_6020C0[i])
异或后就是flag
:
.
.
.
(这里积累第二个经验)
所以总的逻辑梳理一下,用户输入的两个数生成满足i &= i - 1
和v9==10
条件的seed
种子,然后这个这个符合条件的种子生成特定的v9
列表群,最后挑选一个列表md5
加密后满足5eba99aff105c9ff6a1a913e343fec67
的v9
异或LOBYTE(qword_6020C0[i])
就是flag:
.
.
所以参照别人的博客和理解python subprocess模块
后写下自己的脚本:
(注意:kali是运行不了的,会爆error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared object file libc错误)
模块知识博客地址:https://www.cnblogs.com/lincappu/p/8270709.html
import subprocess c=0 seed=[] #v5和v6都是用于生成seed种子,所以可以合并成一步 for i in range(16,65535,1): #源代码中是先i=seed再验证i的符合性,所以逆向的时候就要先验证i的符合性再seed=i while(i): c+=1 i&=i-1 if(c==10): seed.append(i) #获取随机数种子列表,种子固定后rand生成的随机数就会固定。 flag="" for i in seed: #传入符合的i值,其实就是传入一定的seed值, proc=subprocess.Popen(['./zorropub'],stdin=subprocess.PIPE,stdout=subprocess.PIPE); #用subprocess的Popen方法开启proc子进程并用stdin和stdout获取子进程的输入和输出 out=proc.communicate(('1\n%s\n'%i).encode('utf-8'))[0] #传入参数,第一个传入1即可,第二个传入符合的seed种子,第一个无论传入多少生成的seed都只有一个,所以传入1即可。用.encode('utf-8')属性可以传入字符串参数,不然就要传入bytes类型的参数了 if "nullcon".encode('utf-8') in out: print(out) #打印符合的输出字符串 print(i) #打印符合的seed值
.
.
结果:(我运行不了,所以没有结果截图)
nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}
.
.
.
总结:
1: (这里积累第一个经验) 然后分析后半部分,这里先补充一些函数和以前积累的知识:
(以前积累的知识) 这里也是犯下的第二个错误,以前就听过rand是伪随机数,要用
srand
生成随机数种子才行,不然产生的随机数列表都是一样的,而单独产生的随机数也不会在随机数列表用随意取值,而是固定的
第一次这个值,第二次那个值。所以这里我们可以直接修改源代码调试,打印出first_letter的值。函数积累:
int MD5_Init(MD5_CTX *c)
函数: 初始化 MD5 Contex, 成功返回1,失败返回0 .int MD5_Update(MD5_CTX *c, const void *data, size_t len)
函数:
循环调用此函数,可以将不同的数据加在一起计算MD5,成功返回1,失败返回 .int MD5_Final(unsigned char *md, MD5_CTX *c)
函数: 输出MD5结果数据,成功返回1,失败返回0 .unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)
函数:
MD5_Init,MD5_Update,MD5_Final三个函数的组合,直接计算出MD5的值 .void MD5_Transform(MD5_CTX *c, const unsigned char *b)
函数: 内部函数,不需要调用其它积累:
%02x
x 表示以十六
进制形式输出
02
表示不足两位
,,前面补0
输出,如果超过
两位,则以实际输出。
sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]);
的意思是把相当于char的__int8的两位输出到&s1[2*i]中,也就是一次输出两个__int8(char)类型的v11[i]到s1的偶数
地址中,所以相当于一个个
赋值而已。
2:
(这里积累第二个经验)
所以总的逻辑梳理一下,用户输入的两个数生成满足i &= i - 1
和v9==10
条件的seed
种子,然后这个这个符合条件的种子生成特定的v9
列表群,最后挑选一个列表md5
加密后满足5eba99aff105c9ff6a1a913e343fec67
的v9
异或LOBYTE(qword_6020C0[i])
就是flag:
解毕!敬礼!
这篇关于攻防世界逆向高手题之zorropub的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南