easyre
reverse1
reverse2
内涵的软件
新年快乐
xor
reverse3
helloword
不一样的flag
SimpleRev
[GXYCTF2019]luck_guy
Java逆向解密
[BJDCTF2020]JustRE
刮开有奖
[ACTF新生赛2020]easyre
简单注册器
[GWCTF 2019]pyre
findit
[ACTF新生赛2020]rome
RSA
目录结构如下:
RSA
├─flag.enc
└pub.key
解析一下公钥
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMAzLFxkrkcYL2wch21CM2kQVFpY9+7+
/AvKr1rzQczdAgMBAAE=
-----END PUBLIC KEY-----
key长度 | 256 |
模数 | C0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD |
指数 | 65537 (0x10001) |
所以n=86934482296048119190666062003494800588905656017203025617216654058378322103517
e=65535
然后把n放到factordb解一下,得到p=285960468890451637935629440372639283459
q=304008741604601924494328155975272418463
运行以下脚本,得到flag
import rsa
import gmpy2
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
e = 65537
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
D = int(gmpy2.invert(e, (p - 1) * (q - 1)))
private_key = rsa.PrivateKey(n, e, D, p, q)
with open('flag.enc', 'rb+') as f:
flag = f.read()
f.close()
flag = rsa.decrypt(flag, private_key)
print(flag)
[FlareOn4]login
<!DOCTYPE Html />
<html>
<head>
<title>FLARE On 2017</title>
</head>
<body>
<input type="text" name="flag" id="flag" value="Enter the flag" />
<input type="button" id="prompt" value="Click to check the flag" />
<script type="text/javascript">
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}
</script>
</body>
</html>
一眼rot13
import codecs
def rot13(text):
return codecs.encode(text, 'rot_13')
text = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
encoded_text = rot13(text)
print(encoded_text)
[WUSTCTF2020]level1
with open("output.txt", "r") as f:
data = f.read().split("\n")
print(data)
f.close()
for i in range(1, 20):
if (i & 1) == 0:
print(chr(int(data[i - 1]) // i), end="")
else:
print(chr(int(data[i - 1]) >> i), end="")
[GUET-CTF2019]re
用upx去壳后,发现有很多函数,使用字符串搜索找到实际的主函数
发现是sub_4009AE
决定结果,进去看
发现全是这种比较,所以拼接出结果:
conditions = [
(1629056, 166163712),
(6771600, 731332800),
(3682944, 357245568),
(10431000, 1074393000),
(3977328, 489211344),
(5138336, 518971936),
(7532250, 406741500),
(5551632, 294236496),
(3409728, 177305856),
(13013670, 650683500),
(6088797, 298351053),
(7884663, 386348487),
(8944053, 438258597),
(5198490, 249527520),
(4544518, 445362764),
(10115280, 981182160),
(3645600, 174988800),
(9667504, 493042704),
(5364450, 257493600),
(13464540, 767478780),
(5488432, 312840624),
(14479500, 1404511500),
(6451830, 316139670),
(6252576, 619005024),
(7763364, 372641472),
(7327320, 373693320),
(8741520, 498266640),
(8871876, 452465676),
(4086720, 208422720),
(9374400, 515592000),
(5759124, 719890500)
]
a1_values = []
for index, (multiplier, result) in enumerate(conditions):
if index == 6:
a1_values.append(ord("1"))
a1_value = result // multiplier
a1_values.append(a1_value)
print(f"a1[{index}] = {chr(a1_value)}")
print("".join(map(chr, a1_values)))
CrackRTF
进IDA后分析主函数逻辑:
可以看到,第一组密码需要输入一个长度为⑥的数,然后与@DBApp
拼接后,进入sub_40100A
函数后,与6E32D0943418C2C33385BC35A1470250DD8923A9
比较,正确后进去下一部分
分析sub_40100A
函数:
关注到函数CryptCreateHash
,这是一个win32api
其用法如下:
BOOL CryptCreateHash(
[in] HCRYPTPROV hProv,
[in] ALG_ID Algid,
[in] HCRYPTKEY hKey,
[in] DWORD dwFlags,
[out] HCRYPTHASH *phHash
);
关注到第二个参数[in] Algid
,该参数决定了计算的类型,查阅类型表可知,0x8004u
代表计算sha1
于是使用python脚本去碰撞,找到第一个password
import hashlib
string = "@DBApp"
for i in range(100000, 1000000):
if hashlib.sha1((str(i) + string).encode("UTF8")).hexdigest() == "6E32D0943418C2C33385BC35A1470250DD8923A9".lower():
print(f"Password1: {i}")
password1 = i
break
# password1 = 123321
继续分析第二部分
查表可得0x8003u
是MD5
如果运气好,可以在MD5库里找到答案~!3a@0123321@DBApp
如果你没有找到,还是可以继续做(因为发现答案正确,会提示Error
,而且用密码去提交不是flag),直接研究sub_40100F
函数
发现sub_401005
还有对这个值的校验
看起来是个异或的操作,那应该可是可以还原出来而不是去md5库里找
回到sub_40100F
,发现给sub_401005
的值都来自于Resource
中,所以使用Resource Hacker
读取一下AAA的内容
因为我们已知第二部分也是6位,所以取前6个[0x05, 0x7d, 0x41, 0x15, 0x26, 0x01]
然后已知异或的另一部分是dbapp.rtf
的头,所以异或的另一部分是{\rtf1
import hashlib
string = "@DBApp"
for i in range(100000, 1000000):
if hashlib.sha1((str(i) + string).encode("UTF8")).hexdigest() == "6E32D0943418C2C33385BC35A1470250DD8923A9".lower():
print(f"Password1: {i}")
break
# password1 = 123321
part1 = [0x05, 0x7d, 0x41, 0x15, 0x26, 0x01]
part2 = r"{\rtf1"
for i in range(6):
part1[i] ^= ord(part2[i])
print("Password2:", end=" ")
print("".join([chr(i) for i in part1]))
#password2 = ~!3a@0
最后从输出的文件dbapp.rtf
里找到flag
[WUSTCTF2020]level2
UPX之后嗯,直接看到
[2019红帽杯]easyRE
进IDA,发现诡异的类似base64的值
然后解10次base64(PS:为什么是10次呢?因为每次解完后还是像base64,直到第10次x)
在评论区找到答案
找到主函数
[MRCTF2020]Transform
进IDA看到逻辑清晰的主函数
分析主函数可知,flag长为33,按照qword_40F040
中数值的顺序与之异或后比较
[SUCTF2019]SignIn
进IDA反编译
观察到几个重点sub_96A
、一个65537
和__gmpz_powm
这几个构成很像RSA,查询GNU MP库相关函数mpz_init_set_str和mpz_powm 应该是RSA没跑了
解一下大数,得到p和q,然后使用脚本得到flag
[ACTF新生赛2020]usualCrypt
分析主函数
发现比较的部分是word_40E0E4
,把这一块提取出来,然后重点关注函数sub_401080
看起来像是base64,但是直接解不对,所以猜测可能是base64_table
被修改
果然在sub_401000
里发现了蹊跷,还原后还是不对,继续看,发现最后还有一个sub_401030
,分析后得出是大小写转换,最后脚本得出flag
[HDCTF2019]Maze
初见,不会,进IDA,没法分析,百度,需要手动patch然后再分析,记录一下过程
这里jnz产生跳转,但是下面的跳转指令到了0ec85d78dh
这样一个不存在的地址,中断了IDA的自动分析。这种指令成为花指令,因此我们需要把他patch掉,然后让IDA能够自动分析。
IDA就恢复正常了,保存patch,然后重新用IDA打开就可以正常的分析了
初始是7和0,走了13步后变成5和-4,但是这样就会有很多flag的可能,所以继续查看,最后找到maze地图
*******+**
******* **
**** **
** *****
** **F****
** ****
**********
# flag{ssaaasaassdddw}
[MRCTF2020]Xor
进IDA,发现无法使用F5查看反编译结果,不过看流程不复杂,直接分析
前三块的主要内容是读取一个以零结尾的字符串,计算其长度,并检查长度是否为 27
loc_4010B6:
mov al, [edx]
inc edx
test al, al
jnz short loc_4010B6
sub edx, ecx
cmp edx, 1Bh ; 比较 edx 和 27 (1Bh) 的值
jnz short loc_4010FF ; 如果 edx 不等于 27,跳转到 loc_4010FF,表示字符串长度不符合预期
xor eax, eax ; 将 eax 清零(后面比较会用到)
db 66h, 66h
nop word ptr [eax+eax+00000000h]
然后是左侧的几块,用来异或并且与data区0x41ea08
内容比较
loc_4010D0:
mov cl, byte_4212C0[eax] ; 从 byte_4212C0 加上 eax 偏移量的位置读取一个字节到 cl
xor cl, al ; 将 cl 与 al 进行异或操作,结果存回 cl
cmp cl, ds:byte_41EA08[eax] ; 将 cl 与 byte_41EA08 加上 eax 偏移量的位置的字节进行比较
jnz short loc_4010FF ; 如果比较结果不相等,跳转到 loc_4010FF,表示验证失败
inc eax ; 增加 eax 的值,指向下一个字节
cmp eax, edx ; 比较 eax 和 edx,检查是否遍历完所有字节
jb short loc_4010D0
push offset aRight ; "Right!\n"
call sub_401020
push offset aPause ; "pause"
call sub_404B7E
add esp, 8
xor eax, eax
retn
因此,从0x41ea08
拿到数据,然后异或还原即可得到flag
# Python>[idc.get_wide_byte(0x41ea08+i) for i in range(27)]
byte_41EA08 = [0x4d, 0x53, 0x41, 0x57, 0x42, 0x7e, 0x46, 0x58, 0x5a, 0x3a, 0x4a, 0x3a, 0x60, 0x74, 0x51, 0x4a, 0x22, 0x4e, 0x40, 0x20, 0x62, 0x70, 0x64, 0x64, 0x7d, 0x38, 0x67]
for i in range(27):
print(chr(byte_41EA08[i] ^ i), end="")
[MRCTF2020]hello_world_go
额?可能2020年还没IDA pro 8不能这么方便的反汇编?反正直接出结果