Hook Fish
字符串经过加密后,用加载下载的dex的check去检测
可以直接在data找到下载的dex
打开后看到了密文,其他可以直接cope到IDE
然后直接写exp即可(用爆破也可)
public class Main {
public static String decrypt(String encryptedStr) {
char[] encryptedChars = encryptedStr.toCharArray();
for (int i = 0; i < encryptedChars.length; i++) {
char c = encryptedChars[i];
int originalAscii;
if (c >= 'g' && c <= 'y') {
originalAscii = c - '7' - (i % 10);
} else {
originalAscii = (c - (i % 4)) + '1';
}
encryptedChars[i] = (char) originalAscii;
}
code2(encryptedChars, 0);
String hexString = new String(encryptedChars);
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < bytes.length; i++) {
int index = i * 2;
String hexPair = hexString.substring(index, index + 2);
bytes[i] = (byte) Integer.parseInt(hexPair, 16);
}
for (int i = 0; i < bytes.length; i++) {
bytes[i] -= 68;
}
return new String(bytes);
}
private static void code2(char[] a, int index) {
if (index >= a.length - 1) {
return;
}
a[index] ^= a[index + 1];
a[index + 1] ^= a[index];
a[index] ^= a[index + 1];
code2(a, index + 2);
}
public static void main(String[] args) throws Exception {
System.out.println(decrypt("0qksrtuw0x74r2n3s2x3ooi4ps54r173k2os12r32pmqnu73r1h432n301twnq43prruo2h5"));
}
}
Kotlindroid
Base64 + AES/GCM/NoPadding
利用Frida Hook出aad和key
Java.perform(function () {
var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (keyBytes, algorithm) {
console.log('SecretKeySpec constructor called with key: ' + keyBytes);
var byteArrayStr = '';
for (var i = 0; i < keyBytes.length; i++) {
byteArrayStr += String.fromCharCode(keyBytes[i]);
}
console.log('Key byte array as string: ' + byteArrayStr);
return this.$init(keyBytes, algorithm);
};
var JNI = Java.use('com.atri.ezcompose.JNI');
JNI.native_natget.overload('[B').implementation = function (byteArray) {
console.log('native_natget called with byteArray: ' + byteArray);
var byteArrayStr = '';
for (var i = 0; i < byteArray.length; i++) {
byteArrayStr += String.fromCharCode(byteArray[i]);
}
console.log('Byte array content: ' + byteArrayStr);
var result = this.native_natget(byteArray);
console.log('native_natget returned: ' + result);
return result;
};
var jniInstance = JNI.INSTANCE;
var atMethod = jniInstance.getAt;
jniInstance.getAt.implementation = function () {
var result = atMethod.call(jniInstance);
console.log('JNI getAt method returned: ' + result);
return result;
};
});
aad mysecretadd
key atrikeyssyekirta
得到后直接写exp即可
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import java.util.Base64;
public class exp {
public static final String SECRET_KEY = "atrikeyssyekirta";
public static final String ENC = "MTE0NTE0HMuJKLOW1BqCAi2MxpHYjGjpPq82XXQ/jgx5WYrZ2MV53a9xjQVbRaVdRiXFrSn6EcQPzA==";
public static final String AAD = "mysecretadd";
public static void main(String[] args) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(ENC);
byte[] iv = Arrays.copyOfRange(encryptedData, 0, 6);
byte[] cipherText = Arrays.copyOfRange(encryptedData, 6, encryptedData.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, new javax.crypto.spec.SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES"), parameterSpec);
byte[] aad = AAD.getBytes(StandardCharsets.UTF_8);
cipher.updateAAD(aad);
byte[] decryptedBytes = cipher.doFinal(cipherText);
String flag = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println(flag);
}
}
幸运转盘
静态看了半天,懒得打字了,上图吧
exp:
import base64
def rc4_xor(key: bytes, data: bytes) -> bytes:
S = list(range(256))
j = 0
key_length = len(key)
for i in range(256):
j = (j + S[i] + key[i % key_length]) % 256
S[i], S[j] = S[j], S[i]
i = 0
j = 0
out = bytearray()
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
out.append(byte ^ k ^ 40)
return bytes(out)
fixed_key = b"Take_it_easy"
num_list = [101, 74, 76, 49, 101, 76, 117, 87, 55, 69, 118, 68, 118, 69, 55, 67, 61, 83, 62, 111, 81, 77, 115, 101, 53, 73, 83, 66, 68, 114, 109, 108, 75, 66, 97, 117, 93, 127, 115, 124, 109, 82, 93, 115]
result = ""
i=-1
for num in num_list:
i= i + 1
result += chr((num_list[i] ^7 ) -1 )
decoded_data = base64.b64decode(result)
def shift_string(data, shift_value):
shifted_data = bytes([b - shift_value for b in data])
return shifted_data
correct_key = rc4_xor(fixed_key, decoded_data)
shifted_string = shift_string(correct_key, 3)
print(shifted_string)
Fuko's starfish
AES/ECB/NoPadding
找 srand 的交叉引用去掉花指令即可看到key的逻辑
然后直接copy生成key即可(为什么不是C的? 因为当时直接丢给ai的时候想换行结果没按到shift直接发送了,不过也能用)
def c_rand():
global seed
# 模拟 MSVC 的 rand() 算法:
# seed = (seed * 214013 + 2531011) mod 2^32
# 返回值为 (seed >> 16) & 0x7FFF
seed = (seed * 214013 + 2531011) & 0xFFFFFFFF
return (seed >> 16) & 0x7FFF
# 初始化种子,相当于 srand(114514u)
seed = 114514
bytes_list = []
for _ in range(16):
v = c_rand()
# 计算表达式:v + v // 255,并模拟 unsigned char 的截断(取低8位)
byte_val = (v + v // 255) & 0xFF
bytes_list.append(byte_val)
key= ''.join("{:02x}".format(b ^ 0x17) for b in bytes_list)
print(key)
然后用CyberChef一把🔒即可
AndroidLux
当时搞完魔改base64那里就没时间了😭,还是太菜了
下面AndroidLux的题解来自yur0
Android 里运行 linux? 很有趣
Android 那边没什么重要的东西,就初始化了 busybox 的环境,然后开了个 socket 用来通信,看 Service 可以发现他启动了 /root/env
package work.pangbai.androidlux.Service$1;
import java.lang.Runnable;
import work.pangbai.androidlux.Service;
import java.lang.Object;
import java.lang.String;
import work.pangbai.androidlux.cmdExer;
class Service$1 implements Runnable // class@000061 from classes4.dex
{
final Service this$0;
void Service$1(Service this$0){
this.this$0 = this$0;
super();
}
public void run(){
cmdExer.execute("gnu_linux_loader -r /data/data/work.pangbai.androidlux/files -0 -w /root -b /dev -b /proc -b /sys /bin/bash -c ./env", false, true);
}
}
那么文件在哪里呢,题目给了一个 env 文件,这个其实是 tar.gz 格式的,直接可以解压,然后火速去分析 root 目录下的 env
有几个花指令,但是 IDA 很智能,直接帮我们识别出来了,直接 nop 掉就行了
现在逻辑就很清楚了,传进来然后一个魔改 base64 加密了一下
void __fastcall encodeBase64(BYTE *data, int size, BYTE *out)
{
int v3; // w0
int v4; // w1
int v5; // w1
int v6; // w0
int v7; // w1
int v8; // w0
_BYTE *d; // [xsp+58h] [xbp+58h]
int i; // [xsp+68h] [xbp+68h]
int ii; // [xsp+68h] [xbp+68h]
int j; // [xsp+6Ch] [xbp+6Ch]
sqrt((double)25);
j = 0;
if ( size % 3 )
v3 = 4;
else
v3 = 0;
d = malloc(4 * (size / 3) + 1 + v3);
for ( i = 0; i < size; ++i )
{
if ( size - i <= 2 )
{
d[j] = base64[data[i] >> 2];
if ( size - i == 2 )
{
v7 = data[i++] & 3;
d[j + 1] = base64[v7 | ((int)data[i] >> 2) & 0x3C];
d[j + 2] = base64[data[i] & 0xF];
}
else
{
d[j + 1] = base64[data[i] & 3];
d[j + 2] = '=';
}
v8 = j + 3;
j += 4;
d[v8] = '=';
}
else
{
d[j] = base64[data[i] >> 2];
v4 = data[i] & 3;
ii = i + 1;
d[j + 1] = base64[v4 | ((int)data[ii] >> 2) & 60];
v5 = data[ii] & 15;
i = ii + 1;
d[j + 2] = base64[v5 | (16 * (data[i] >> 6))];
v6 = j + 3;
j += 4;
d[v6] = base64[data[i] & 0x3F];
}
}
d[j] = 0;
*(_QWORD *)out = d;
}
密文: RPVIRN40R9PU67ue6RUH88Rgs65Bp8td8VQm4SPAT8Kj97QgVG==
自定义表: TUVWXYZabcdefghijABCDEF456789GHIJKLMNOPQRSklmnopqrstuvwxyz0123+/
base64 魔改点就在将第二部分的前 2 个 bit 和后 4 个 bit 互换,第三部分的前 4 个 bit 和后 2 个 bit 互换,其他不变
但是尝试解码的时候出现了问题,R
查表得到 40,转二进制就是 101000
,第一个字符的最高位是 1?这不符合可打印字符的范围,说明这题还有其他地方藏了逻辑
在把这个程序翻了个底朝天也没找到东西后,只能看看是不是这个环境哪里对程序做了修改,掏出我们的 everything, 按时间排序一下文件,看看出题人在哪里干了坏事
接着就翻到了 ld.so.preload
文件,加载了 /usr/libexec/libexec.so
果不其然,在这个 so 里面 hook 了 read
和 strcmp
函数
那么逻辑已经十分清晰了,exp:
def custom_rot13_decrypt(data: str) -> str:
dec = []
for c in data:
if 'A' <= c <= 'M' or 'a' <= c <= 'm':
dec.append(chr(ord(c) + 13))
elif 'N' <= c <= 'Z' or 'n' <= c <= 'z':
dec.append(chr(ord(c) - 13))
else:
dec.append(c)
return ''.join(dec)
cipher_text = "RPVIRN40R9PU67ue6RUH88Rgs65Bp8td8VQm4SPAT8Kj97Qg"
table = list("TUVWXYZabcdefghijABCDEF456789GHIJKLMNOPQRSklmnopqrstuvwxyz0123+/")
eee = custom_rot13_decrypt(cipher_text)
enc = eee.encode()
print(enc)
idx = []
for i in enc:
idx.append(table.index(chr(i)))
s = []
for i in idx:
s.append(bin(i)[2:].zfill(6))
for i in range(0, len(s), 4):
s[i + 1] = s[i + 1][4:] + s[i + 1][:4]
s[i + 2] = s[i + 2][2:] + s[i + 2][:2]
res = ""
for i in s:
res += i
b = [res[i:i+8] for i in range(0, len(res), 8)]
for i in b:
print(chr(int(i, 2) ^ 1), end="")
print("}")
# VNCTF{Ur_go0d_@ndr0id&l1nux_Reve7ser}