NSSCTF Round#22 Reverse个人专项赛 WP

2024-04-19 22:04

本文主要是介绍NSSCTF Round#22 Reverse个人专项赛 WP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. ezcrypt(史)

pyinstxtractor.py解包exe,然后pycdc反编译NSSCTF.pyc

得到的源码并不完整,但是重要的部分已经有了,就是一个blowfish加密

但是密钥是crypto.SomeEncode,这并不是字面意义的字符串,而是引用的其他文件

NSSCTF.exe_extracted可以找到可疑文件crypto.cpython.pyc

是一个魔改的TEA(这里出题逻辑有问题,按给的代码逻辑SomeEncode是v加密得到的,但实际上却要我们解密得到)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{unsigned int enc[5] ={1396533857,0xCC8AE275,0x89FB8A63,940694833};unsigned int key[4] ={17,34,51,68};int i, j;for (i = 0; i < 4; i += 2){unsigned int v0 = enc[i], v1 = enc[i + 1], sum = 0xC6EF3720;unsigned int delta = 0x9e3779b9;unsigned int k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3];for (j = 0; j < 32; j++){v1 -= ((v0 << 3) + k2 ^ v0 + sum ^ (v0 >> 4) + k3 ^ 2310) & 0xFFFFFFFF;v0 -= ((v1 << 3) + k0 ^ v1 + sum ^ (v1 >> 4) + k1 ^ 596) & 0xFFFFFFFF;sum -= delta & 0xFFFFFFFF;}enc[i] = v0; enc[i + 1] = v1;}for (i = 0; i < 4; i++){printf("%u ", enc[i]);}printf("%s", enc);//sNzEveRsjorPstcereturn 0;
}

这里有个每四位一个逆序(第三行就是ASCII转字符的意思),解出来手动改一下吧,就是 EzNssRevProjects

#ezcrypt wp
from Crypto.Cipher import Blowfish  
from Crypto.Util.Padding import unpad  
from Crypto.Random import get_random_bytes  def decrypt_file(input_path, output_path, key):  with open(input_path, 'rb') as f:  # 读取整个文件内容,包括IV和密文  data = f.read()  # 分割IV和密文  iv = data[:Blowfish.block_size]  print(iv)ciphertext = data[Blowfish.block_size:]  print(ciphertext) # 验证密钥长度  #if len(key) != Blowfish.key_size:  #    raise ValueError("Invalid key size for Blowfish. It must be exactly 8 bytes long.")  # 创建一个新的Blowfish cipher对象,并设置密钥和IV  cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv=iv)  # 解密数据  plaintext = (cipher.decrypt(ciphertext), Blowfish.block_size)  print(plaintext[0])# 将解密后的数据写入输出文件  with open(output_path, 'wb') as f:  f.write(plaintext[0]) key = b'EzNssRevProjects'
input_path = 'D:\\下载\\CTF附件\\NSS22re\\output'
output_path = 'D:\\下载\\CTF附件\\NSS22re\\flag'decrypt_file(input_path, output_path, key)

密钥解码得到一个二进制文件,IDA打开是个虚拟机(笑)

动调不出来(这里逻辑也莫名其妙,明明这个代码就应该能跑出flag,但实际上是要你把代码反过来写)

硬做,动调取出opcode,key

VM函数抄下来符号改一下,有个地方给的代码还不对,看汇编也是sub

这里应该是加号

#include<stdio.h>
__int64 __fastcall vm(unsigned char* a1, int* a2, int a3)
{__int64 result; // raxint i; // [rsp+1Ch] [rbp-8h]int v5; // [rsp+20h] [rbp-4h]for (i = 0; ; ++i){result = i;if (i >= a3)break;v5 = i % 4;if (i % 4 == 3){a1[i] -= a2[8] + a2[0];}else if (v5 <= 3){if (v5 == 2){a1[i] += a2[4] ^ a2[12];}else if (v5 <= 2){if (v5){if (v5 == 1){a1[i] ^= a2[0] - a2[8];}}else{a1[i] ^= a2[16] + a2[4];}}}}return result;
}
int main()
{unsigned char opcode[] ={0x37, 0x8D, 0x0F, 0xAB, 0x2D, 0x98, 0x37, 0xB5, 0x48, 0xA6,0x30, 0xDA, 0x0C, 0xED, 0x1B, 0xB8, 0x00, 0xE9, 0x24, 0x98,0x17, 0x81, 0xED, 0xB6, 0x26, 0x8C, 0x21, 0xDE, 0x04, 0xDE};int key[] ={0x23, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x45, 0x00,0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x67};vm(opcode, key, 30);printf("%s", opcode);//NSSCTF{M1xtru3_Py7h0n_1N_Rev}return 0;
}
2. EzHook

看起来只是异或,但是最后的字符有?很奇怪

联系题目实际上使用了Windows IAT Hook技术

动调试试,断在密文处

随你怎么输都是走左边

F8到MessageBoxA这里F7进去

进到另一个函数里,应该是hook注入的函数

这里是真正的提示分支,qword_7FF63596A090应当是真实的MessageBox

我们注意所有输入在78行xxtea加密之后,经过密文比较。又在83和88行解密

只要在解密之前把输入a2改成密文Str2即可

a2应该存在rcx寄存器里

每16个地址Change byte一次,把对应的密文填进去

然后跑到这里,a1点进去

3. 简简又单单

jadx打开

md还是个魔改XTEA

#include<stdio.h>
void xtea_decipher(unsigned int num_rounds, unsigned int v[2], unsigned int const key[4]) {unsigned int i;unsigned int v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds;for (i = 0; i < num_rounds; i++) {v1 -= ((((v0 << 4) ^ (v0 >> 5)) + v0)^918) ^ (sum + key[(sum >> 11) & 3]);sum -= delta;v0 -= ((((v1 << 4) ^ (v1 >> 5)) + v1)^918) ^ (sum + key[sum & 3]);}v[0] = v0; v[1] = v1;
}
int main()
{unsigned int enusr[] = { 0x3c36eb49,0x81acb0c0,0xfac269ae,0xca5bf9ec }; // 密文unsigned int key[4] = { 0x12345678, 0x5678ABCD, 0x89ABCDEF, 0xCDEF1234 }; // 密钥for (int i = 0; i < 4; i += 2) {unsigned int tmp[2] = { 0 };tmp[0] = enusr[i];tmp[1] = enusr[i + 1];xtea_decipher(32, tmp, key);enusr[i] = tmp[0];enusr[i + 1] = tmp[1];}printf("%s", enusr);//NS5_R0Un6_z2_apKreturn 0;
}

密码看不到,因为在native层中

解压apk文件,找到so文件

可以搜到相应的函数

Java_com_example_nss_MainActivity_validatePassword内可以找到密文

应该是RC4加密过,但是脚本跑不出,又魔改了

Java_com_example_nss_MainActivity_encryptWithRC4看看

改成了128轮加密

加密密钥是用户名

#ez_APK wp
def rc4(data, key):S = list(range(128))j = 0out = []for i in range(128):j = (j + S[i] + key[i % len(key)]) % 128S[i], S[j] = S[j], S[i]i = j = 0for char in data:i = (i + 1) % 128j = (j + S[i]) % 128S[i], S[j] = S[j], S[i]out.append(char ^ S[(S[i] + S[j]) % 128])return bytes(out)data = bytes.fromhex("572e180b1a680b3e5276344b241d5b52525a043173346b1355442028")
key = b'NS5_R0Un6_z2_apK'
decrypted = rc4(data, key)
print(decrypted)
#NSSCTF{V3ry_4z_1ib_W1th_4pk}
4. GO!GO!GO!

shell看不出东西,分析主文件

好像是调用了shell

大量的WinAPI调用,有个函数进去看看

似乎是要卸载表面上的内存映像,注入傀儡进程

查询qword_140005080的交叉引用定位到

动调发现qword_140005080内资源开头为MZ,是PE文件

ResourceHacker正好可以提取

非常恶心go语言

这是输入的key1,可以用hashcat爆破

hashcat -m 0 -a 3 b098cacb2d43b882ef9a83168d13c3a7 ?a?a?a?a?a?a

稍等一段时间,烧一会GPU就出来了 G0@K3y

key2是一个道理

hashcat -m 1400 -a 3 c32a69f4609191a2c3e6dbe2effc329bff20617230853462e8745f2c058bec2f ?a?a?a?a?a?a

得到n3SC1f

又输入一段东西进了main_Function2

第三次输入的就是flag

发现RC4特征

有魔改,但是无所谓直接动调

先找一下RC4的密钥,应该和之前的输入有关

看到密钥被拼接了

由于RC4是对称加密,所以可以考虑把密文提出来再写入用原程序解密

先动调取出密文

然后重新动调,找到存储flag的内存位置

patch成密文

动调到加密之后

这篇关于NSSCTF Round#22 Reverse个人专项赛 WP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/918551

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank&nbsp;正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money

分布式系统的个人理解小结

分布式系统:分的微小服务,以小而独立的业务为单位,形成子系统。 然后分布式系统中需要有统一的调用,形成大的聚合服务。 同时,微服务群,需要有交流(通讯,注册中心,同步,异步),有管理(监控,调度)。 对外服务,需要有控制的对外开发,安全网关。

Java IO 操作——个人理解

之前一直Java的IO操作一知半解。今天看到一个便文章觉得很有道理( 原文章),记录一下。 首先,理解Java的IO操作到底操作的什么内容,过程又是怎么样子。          数据来源的操作: 来源有文件,网络数据。使用File类和Sockets等。这里操作的是数据本身,1,0结构。    File file = new File("path");   字

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析

2025届计算机毕业设计:如何构建Java SpringBoot+Vue个人健康档案管理系统?

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 | SpringBoot/SSM Python实战项目 | Django 微信小程序/安卓实战项目 大数据实战项目 ⚡⚡文末获取源码 文章目录

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>