分类
偶拾一叶

[BUUCTF]Reverse: rsa

两个文件:pub.key、flag.enc

vs code打开pub.key,是个公钥的样子。

-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMAzLFxkrkcYL2wch21CM2kQVFpY9+7+
/AvKr1rzQczdAgMBAAE=
-----END PUBLIC KEY-----

然后用python的rsa模块解密会报错,像是格式不对。

pubkey = rsa.PublicKey.load_pkcs1(pk)

# raise ValueError('No PEM start marker "%r" found' % pem_start)

于是换成Crypto.PublicKey.RSA,可以了。

pubkey = Crypto.PublicKey.RSA.importKey(pk)
print(pubkey)
print(pubkey.n, pubkey.e)

# <_RSAobj @0xffff94d979d0 n(256),e>
# 86934482296048119190666062003494800588905656017203025617216654058378322103517 65537

用factordb.com对n做分解,可以解出p和q,然后就简单了,以下是脚本。

import gmpy2
import rsa
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

with open('./pub1.key',mode='rb') as fpk:
    pk = fpk.read()
# pubkey = rsa.PublicKey.load_pkcs1(pk)
pubkey = RSA.importKey(pk)
print(pubkey)
print(pubkey.n, pubkey.e)

n = 0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD
e = 65537
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phi = (p-1) * (q-1)
d = gmpy2.invert(e, phi)

with open('./flag.enc','rb+') as ff:
    cdata = ff.read()

# 用Crypto库,试了N次都报错,放弃了
# rsadata = RSA.construct((n, e, int(d), p, q))
# key1 = RSA.importKey(rsadata.exportKey())
# key1 = PKCS1_OAEP.new(key1)
# print(key1)
# print(key1.decrypt(cdata))

# rsa模块直接搞定
key = rsa.PrivateKey(n, e, int(d), p, q)
print(rsa.decrypt(cdata, key))

# Public RSA key at 0xFFFFA511FF10
# 86934482296048119190666062003494800588905656017203025617216654058378322103517 65537
# b'flag{decrypt_256}\n'

分类
偶拾一叶

密码保护:此身虽在堪惊

此内容受密码保护。如需查阅,请在下列字段中输入您的密码。

分类
CTF Reverse

[攻防世界]Reverse: xxxorrr

IDA64打开,函数乱七八糟的一堆。

main函数是这样,看到输入,但没看到输出。

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+Ch] [rbp-34h]
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  sub_A90(sub_916, a2, a3);
  fgets(s, 35, stdin);
  for ( i = 0; i <= 33; ++i )
    s1[i] ^= s[i];
  return 0LL;
}

看strings发现Congratulations和Wrong,反查,发现输出结果的函数在sub_916。

unsigned __int64 sub_916()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  if ( !strcmp(s1, s2) )
    puts("Congratulations!");
  else
    puts("Wrong!");
  return __readfsqword(0x28u) ^ v1;
}

main里面也出现了sub_916,是不是一个事件注册或者回调之类的,没有能力深究。但总之sub_916里,会比较s1和s2。双击发现s1和s2都有初值。

按main里写的,flag应该就是s1和s2逐项异或的结果,但结果是“'/$ 2(}!d''":/m-TA*$INçÞ”,不是答案。

然后逐个翻了翻函数,发现一个sub_84A也对s1做了操作。

unsigned __int64 sub_84A()
{
  int i; // [rsp+Ch] [rbp-14h]
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  for ( i = 0; i <= 33; ++i )
    s1[i] ^= 2 * i + 65;
  return __readfsqword(0x28u) ^ v2;
}

于是把这个异或也加上,就算出了flag。

s1 = 'qasxcytgsasxcvrefghnrfghnjedfgbhn' + chr(0x20)
s2 = '564E5758515109461746545A59591F48325B6B7C756E7E6E2F774F7A71432B2689FE'
flag = ''
for i in range(34):
    flag += chr(ord(s1[i]) ^ (2*i+65) ^ int(s2[2*i:2*i+2],16))
print(flag)

# ┌──(.venv)─(kali㉿kali)-[~/ctf]
# └─$ /home/kali/ctf/.venv/bin/python /home/kali/ctf/xor.py
# flag{c0n5truct0r5_functi0n_in_41f]

但是为什么会有这么一个sub_84A呢?找找原因。

首先在函数名字上右键,找引用,发现init函数里面有一个func_A59变量的值等于sub_840。也就是for循环里调用了sub_84A,但还是没明白机制。

void __fastcall init(unsigned int a1, __int64 a2, __int64 a3)
{
  signed __int64 v4; // rbp
  __int64 i; // rbx

  v4 = &off_200D98 - &funcs_A59;
  init_proc();
  if ( v4 )
  {
    for ( i = 0LL; i != v4; ++i )
      ((void (__fastcall *)(_QWORD, __int64, __int64))*(&funcs_A59 + i))(a1, a2, a3);
  }
}

不过至少知道了main并不一定是第一个执行的函数,应该看一下main被哪个函数引用,然后看看这个函数里有没有在main前面执行什么。

分类
偶拾一叶

密码保护:人生的郁闷经历

此内容受密码保护。如需查阅,请在下列字段中输入您的密码。

分类
CTF Reverse

[BUUCTF]Reverse: FindIt

题目:不知不觉,小明长大了,变成了一个程序员,……代表月亮惩罚小明!得出答案。

下载之后解压,是一个apk,用jed打开,找到核心代码。看了下,分别有两个循环,计算两个字符串。

解出第一个字符串之后,如果安装apk的话,输入这个字符串,估计就能得到flag。

但第二个循环可以直接算出flag,当然用第二个了。直接复制粘贴java代码,稍作修改。

public class Findit {
    public static void GetFlag(){
        char[] x = new char[17];
        char[] y = new char[38];
        int i;
        for(i = 0; i < 17; ++i) {
            if(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] < 73 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 65 || new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] < 105 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 97) 
            {
                x[i] = (char)(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] + 18);
                    
            }
            else if(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 65 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] <= 90 || new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 97 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] <= 0x7A) 
            {
                x[i] = (char)(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] - 8);
            }
            else {
                x[i] = new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i];
            }
        }

        System.out.println(x);

        if(true) {  // id:widget2
            int v0_1;
            for(v0_1 = 0; v0_1 < 38; ++v0_1) {
                if(new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1] >= 65 && new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1] <= 90 || new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1] >= 97 && new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1] <= 0x7A) 
                {
                    y[v0_1] = (char)(new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1] + 16);
                    if(y[v0_1] > 90 && y[v0_1] < 97 || y[v0_1] >= 0x7A) 
                    {
                        y[v0_1] = (char)(y[v0_1] - 26);
                    }
                }
                else {
                    y[v0_1] = new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v0_1];
                }
            }

            System.out.println(y);  // id:widget1
            return;
        }
    }
    public static void main(String[] args) {
        GetFlag();
    }
}

运行结果如下,第一行就是第一个字符串,安装apk后输入,应该就能得到flag。

PS E:\Personal\Desktop> java Findit
LzakAkLzwXdsyZgew
flag{c164675262033b4c49bdf7f9cda28a75}
分类
CTF Reverse

[BUUCTF]Reverse: [ACTF新生赛2020]easyre1

这道题目解压出来有一堆exe,看了下两个小的exe,感觉没什么用。

用DIE打开easyre.exe,发现有upx壳,解之,然后ida32打开,找到主函数。

V6实际上就是ACTF{,V10是},二者组成flag的外圈,里面应该有12个字符,因为for循环中i从0到11。for循环看起来是比较①V4[i] ②__data_start__数组中索引为V5[i]-1的值。

点开_data_start__,看到一串文本。

这里问题来了,我试了好几次,导出数据总是被截断,如下图,我也不知道为什么,在buuctf群里问了,时间太晚暂时还没有师傅帮忙。

最后我只好把这个数组一行一行站到了代码里。

v4 = "*F'\"N,\"(I?+@"
data = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""

res = ''
for x in v4:
    v5i = data.find(x) + 1 
    res += chr(v5i)

print(res)

运行得到U9X_1S_W6@T?,加上flag包围即可。buuctf的题要把ACTF换成flag,即flag{U9X_1S_W6@T?}

分类
CTF Reverse

[BUUCTF]Reverse: 简单注册器

下载后,是一个apk文件。用jed打开,找到核心代码。

看起来有两种解法,要么是根据第一个if的条件,判断要输入什么字符,然后安装这个apk,输入之后能看到flag;要么是根据第二个if做了什么,来写代码计算出flag。我选了第二个,感觉装apk麻烦。

本来想写python,但忽然想到为什么不用java,虽然我没用过java,但运行一下代码应该还行。

然后到菜鸟教程学了下,总结跑单个java文件的方法:

  1. 写个类,保存成java文件,文件名和类名一致(例如CTest.java)。类中包含main函数;
  2. 到命令行,先运行javac CTest.java,然后运行java CTest即可。

Java代码如下:

public class CTest {
    public static void main(String[] args) {
        char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
        x[2] = (char)(x[2] + x[3] - 50);
        x[4] = (char)(x[2] + x[5] - 0x30);
        x[30] = (char)(x[0x1F] + x[9] - 0x30);
        x[14] = (char)(x[27] + x[28] - 97);
        int i;
        for(i = 0; i < 16; ++i) {
            char a = x[0x1F - i];
            x[0x1F - i] = x[i];
            x[i] = a;
        }
        System.out.println("flag{" + String.valueOf(x) + "}");
        return;
    }
}

运行结果:

PS E:\Personal\Desktop> javac CTest.java
PS E:\Personal\Desktop> java CTest
flag{59acc538825054c7de4b26440c0999dd}
分类
偶拾一叶

做CTF的Re题真累

刚才ida出来个switch,忽然怀念我的NS了。

每次在反汇编的一堆比乱码还烦的东西里挣扎的时候,都会想,何必自己难为自己。

(应该配个反汇编的switch和ns的比较图,懒得弄了)

分类
偶拾一叶

旧域名,新博客

现在是2022年8月15日03:56:33,终于架好了这个博客。

下面首先要考虑数据库备份以及文件备份问题。