攻防世界Reverse(5)
secret-string-400
后缀为gz,第一次见这种压缩包!
当然我们也可以直接就去用ida看看,是可以发现无法进行逆向的,所以我们解压它!
有点像web题型,不过它是给了代码的!
我们打开看看!
这是用火狐打开所显示的内容,用IE打开是没有办法完整显示的,此时我们再来看看另一个html页面!
有意思!没想到是个这样子的逆向!
然后源代码是没有相关内容的,但是再js里面有,所以我们可以找到js,用记事本打开即可!
然后我们在调试器中进行一系列调试!
不过调试结果在console显示必须在run函数加上一句话!
此时我们便可以根据代码写出解密脚本!
WOW_so_EASY
flag就有了!
这道题主要考察了对与网页web上的一些简单登录进行的逆向!主要是加的那句话,将代码给泄露出来!然后根据其进行逆向!
testre
做题来了手感!赶紧再做一题!
EP先探查没有什么东西!
主要就是这个检查函数,所以我们就进去里面进行一番探查!
再到函数上面进行细致分析!
base58不是2的整次幂,所以原理不是base64那样子。
flag{base58_is_boring}
flag就有了,主要是要理解这个base58是个什么东西!
base58编码,其实源于比特币!
base58编码先将输入转换为ASCLL码值(按256进制算!),然后转换为10进制的数,然后转换为58进制数,此时我们将其按照base58表转换!
deedeedee
这道题还是很难(简单的,flag直接给了)解压有两个文件。
D语言最初由Digital Mars公司就职的Walter Bright于2001年发布,意图改进C++语言。目前最新D语言被简称为D2。最主要的D语言的实现是DMD。
有个后缀名为d的文件,用记事本打开,发现有代码!
import std.stdio;
import std.range;
import std.algorithm;
import std.string;
import std.traits;
import std.conv;
template enc(string key) {
string enc(string s) pure @safe {
pragma(msg, "encrypting with key...", key);
char enc_add = cast(char) (s.length.to!int);
string output = "";
foreach(a,b; cycle(key).zip(s)) {
output ~= a ^ b ^ enc_add;
}
return output;
}
}
mixin template ForeachUnrolled(string F, int N, int MIN=1) {
pragma(msg, "ForEach...", N, " to ", MIN);
static if (N > 1) {
mixin ForeachUnrolled!(F, N-1, MIN);
}
mixin MakeFunction!(F, N);
}
mixin template MakeFunction(string F, alias T) {
// Convert $ and %
mixin(translate(F, ['$' : T.to!(string), '%' : (T-1).to!string]));
}
string encrypt(string s) pure @safe {
const int n = 499; // 500 is DMD's template recursion limit
//const int n = 30;
string output_0 = s; // base case with our string
mixin ForeachUnrolled!("string output_$ = enc!($$$.to!string)(output_%);", n);
mixin("return output_" ~ n.to!string ~ ";");
}
string hexencode(string s) {
string encoded = "";
foreach (c; s) {
encoded ~= format("%02x", c);
}
return encoded;
}
string enc_flag = encrypt("flag{t3mplat3_met4pr0gramming_is_gr8_4_3very0n3}");
void main() {
writeln("Your hexencoded, encrypted flag is: ", enc_flag.hexencode);
writeln("I generated it at compile time. :)");
writeln("Can you decrypt it for me?");
}
这里其实很显眼的可以看到flag的存在!
如果没有源代码做的话,估计要远程调试!
此时我们接着调试!
调试半天不出来!
这里先空着!等有时间再看看!
zorropub
里面有许多字符,经过翻译是个劝酒喝酒喝饮料的程序。
EP再ida打开去分析里面的一些内容!
对了,这里有句话说错了,就是v6是在16之上!接着看看!
大致理解了里面的思路,我便用kali进行运行但是报错了!
所以这个思路是行不通的!
此时再来列一下各个函数
MD5Init是一个初始化函数,初始化核心变量,装入标准的幻数
MD5Update是MD5的主计算过程
MD5Final整理和填写输出结果
int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。
好了,就说这么多吧,最简单的思路就是爆破!
首先是用pwntools库来进行爆破,但是这样子没能成功
from pwn import *
a = []
for v6 in range(16,0xffff):
v9 = 0
seed = 0
seed ^= v6
i = seed
while(i):
v9 = v9 + 1
i &= i - 1
if v9 == 10:
a.append(v6)
for i in a:
try:
r = process('./87356aae634e4e0a9a081f30fc81fe16')
r.recv()
r.sendline('1')#这里会出错,不知这么回事?
r.recv()
r.sendline(str(i))
r.recv()
if "null" in text:
print(text)
break
except:
continue
r.close()
这样子总是会出错!
但是不要着急,还有一个重要的库python subprocess模块
通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
然后我看到它是64位,不能用OD,就想打开xdbg64,但是还是不行,因为他是个ELF文件!dgb又不想用,就放这吧!
nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}
BabyXor
这里首先进行EP探查,发现有个壳,但是属于未知壳,所以还是使用OD进行脱壳,进入是会提示说代码有压缩,我们不用管!
然后使用ODdumop插件进行脱壳!生成一个新的没有壳的文件!然后就可以用ida进行打开了,不过时无法进行运行的!但是我们静态分析已经足够了!
来来分析一波这道题!
进去!
memcpy指的是C和C++使用的内存拷贝函数,函数原型为void *memcpy(void *destin, void *source, unsigned n);函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
sprintf指的是字符串格式化命令,函数声明为 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。
我们此时不知道flag是在哪里出现的,所以我们以我们模仿其进下写个脚本,然后将每个过程打印一下就可以了!
array1 = [102,109,99,100,127,55,53,48,48,107,58,60,59,32]
array2 = [55,111,56,98,54,124,55,51,52,118,51,98,100,122]
array3 = [26,0,0,81,5,17,84,86,85,89,29,9,93,18,0,0]
上面是三个数组,此时我再分别看看异或的函数!
再来看看第二个异或函数!
和第三个异或函数!
此时我们再将其整合到一起!
对了,这个图片了的最后一句话有点毛病,不用管它!
脚本!来来来!
array1 = [102,109,99,100,127,55,53,48,48,107,58,60,59,32]
array2 = [55,111,56,98,54,124,55,51,52,118,51,98,100,122]
array3 = [26,0,0,81,5,17,84,86,85,89,29,9,93,18,0,0]
v3 = ''
for i in range(14):
v3 += chr(array1[i]^i)
v5 = ''
v5 += (chr(array2[0]))#这里就是整合时候添加进去的一个字符!没有这个字符结果会大不一样
for i in range(1,14):
v5 += chr(array1[i]^array2[i]^array1[i-1])
v7 = ''
for i in range(13):
v7 += chr(ord(v5[i])^i^array3[i+1])
byte = chr(array2[0]^array3[0])#这里是在第三个异或函数里面进行添加的字符
print(v3,end='')
print(v5,end='')
print(byte,end='')
print(v7,end='')
梅津美治郎
这道题的描述确实很激荡人心!
解压后是个exe文间,所以先EP探查!
然后看下面:
然后我们找找v8是个啥?
此时我们就知道了如何通过这一关,但是后面一关看看sub_4015EA这个函数!
不过此时我们用另一神器OD看看!
然后进到第二步里面看看!
正好对着ida里面的函数!
这里确实陷入了困境!
到这里我改用ida本地调试!
这里用的是远程windows调试(其实也可以再本地调试!因为我就是在本地调试的!)先找!
此时我们再打开ida去远程连接它!
可能你有点疑惑,它这么没有文件名呢?你直接一路确定到最后回弹出一个窗口让我们选择要调试的程序!
此时我们来进行调试就很方便了!比OD要方便好多!
接着调,调它到天荒地老!然后就跳出来了,但是第二个密码是什么呢?
__debugbreak函数,这个是个关键点,在x86中汇编指令就变成了init 3这个断点了,但是还是不能够解决这个问题,所以我又回到ida静态分析了,发现了一个特殊的地方!
此时我用OD打开,先在运行完跳到该函数里,但是运行着就ret了,所以我们跳到判断语句中也是一条思路!
此时因为OD和ida远程调试调试不到函数回调!所以我们直接看代码(静态分析)函数回调,这表明这我们可以在ida中找到的,不过位置是不好确定的,只能凭借自己的经验和一步一步分析来了!
此时我们可以进去看看!
但是值我们是找不到的,所以我们还是需要进行函数回调,异常回调函数在汇编中是个init 3断点,我们一般会直接修改它,但是修改了就不会进行异常函数回调了!
然后我们从栈上追踪数据!找到了函数回调的原始数据!
这样子我们模拟一个函数回调的异或运算来进行解密!
a = [0x75,0x31,0x6E,0x6E,0x66,0x32,0x6C,0x67]
for i in a:
print(chr(i^2),end='')
flag{r0b0RUlez!_w3lld0ne}
easyCpp
这个刚开始看的话,确实有点看不下去!所以我直接动态调试,调试到最后看看能不能出flag!
所以我又开始了静态分析!
此时我们可以去fib函数里面看看!
这里是个递归!最后应该将数列储存在了LODWORD(v29)这里了!
C++的确实这里没有学过!
容器(Containers) 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
算法(Algorithms) 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
迭代器(iterators) 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。
STL的知识确实没有学习过,这里其实是凭借着经验主义来行事的!
然后我们进去看看!
此时我们就需要搞懂这两个函数到底时干什么的!
然后再经过循环看看结果,从而推导出这里的加密方式!
还有就是分析的时候要注意是地址还是地址里面的内容!
那个判断应该就是判断是否输入与斐波那契数列是否一致!
这样的话是可以找到我们要输入什么,知道了输入什么正确也就意味着flag找到了!
此时我们就可以开始写脚本了!
def fib(i):#模拟斐波那契数列
if not i or i == 1:
return 1
j = fib(i - 1)
return j + fib(i - 2)
data = [0] * 16
j = 15
for i in range(16):
data[j] = fib(i)
j -= 1
print(data)#模拟逆序
for i in range(1,len(data)):#模拟将其进行斐波那契规律
print(data[i] - data[0])
然后输入这个数组就可以了!