暑假第七周
[湖湘杯2018]HighwayHash64
HighwayHash是是伪随机的 函数(即键控散列函数)优化了速度 信息,由Jyrki Alakuijala、Bill Cox和Jan Wassenberg设计 谷歌研究
我看有大佬WP是通过导入HighwayHash-cffi包用python来爆破的
但我没安装成功,贴个博客地址
先运行看看回显
ida打开查看主函数有两处check
法一
两处check的retcode都是1,可以把第二处修改为2,爆破第一处check得到长度
第二处check地址为1400019D6
010edit修改
写个bat爆破长度
@echo off
:next
reverse.exe
if %ERRORLEVEL% EQU 2 echo !!!!!get_len!!!!! & goto next
if %ERRORLEVEL% EQU 1 echo again & goto next
if %ERRORLEVEL% EQU 0 echo ############ & goto next
可以得到flag长度为19,除去hxb2018{}
中间数字有10位
对照github上HighwayHash源码分析sub_1400017A0函数
其中HighwayHashReset是修改过的
将下载下来的源码highwayhash.c里的HighwayHashReset修改
可以通过第一个check验证一下我们的修改是否正确
#include "highwayhash.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const uint64_t key[4]={0};
uint8_t data[11] = {19};
printf("%llx",HighwayHash64(data, 4, key));
return 0;
}
结果正确,说明我们的修改是符合题目所给的,那我们就可以爆破了
exp
#include "highwayhash.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const uint64_t key[4]={0};
uint8_t data[11]={0,0,0,0,0,0,0,0,0,0};
for(uint8_t v1='9';v1>='0';v1--){
for(uint8_t v2='9';v2>='0';v2--){
for(uint8_t v3='9';v3>='0';v3--){
for(uint8_t v4='9';v4>='0';v4--){
for(uint8_t v5='9';v5>='0';v5--){
for(uint8_t v6='9';v6>='0';v6--){
for(uint8_t v7='9';v7>='0';v7--){
for(uint8_t v8='9';v8>='0';v8--){
for(uint8_t v9='9';v9>='0';v9--){
for(uint8_t v10='9';v10>='0';v10--){
data[0]=v1;
data[1]=v2;
data[2]=v3;
data[3]=v4;
data[4]=v5;
data[5]=v6;
data[6]=v7;
data[7]=v8;
data[8]=v9;
data[9]=v10;
if(HighwayHash64(data, 10, key) == 0xC886BDF39CB4ED72){
puts((char *)data);
}
} } } } } } } } } }
return 0;
}
大概2-3分钟跑出结果
法二
调用函数有两种方法,一种是写一个dll注入到exe中进行调用,另一种则是将该exe直接改成dll,另外写一个exe来调用
考虑后者将exe修改成dll
可以用010editor修改pe的NT头
- IMAGE_FILE_HEADER->Characteristics(文件属性)->2102h(DLL文件一般是2102h)
- IMAGE_OPTIONAL_HEADER->AddressOfEntryPoint(程序执行入口RVA)->0000h
或者用DIE的PE菜单修改
exp
//#include "pch.h"
#include <iostream>
#include<windows.h>
typedef __int64(__fastcall *f)(__int64 buff, unsigned __int64 len);
f func;
void len()
{
int i;
unsigned long long result;
for (i = 0; i < 50; i++)
{
result = func((long long)&i, 4);
if (result == 0xD31580A28DD8E6C4)
{
printf("Len is %d\n", i - 9);
return;
}
}
printf("Not found the lenn");
return;
}
void hash()
{
unsigned long long i;
unsigned long long result;
char buff[20];
for (i = 10000000000; i > 0; i--)
{
sprintf_s(buff, "%0.10llu", i);
/*if (i % 100000 == 0)
{
printf("%0.10llu\n", i);
}*/
result = func((long long)buff, 10);
if (result == 0xC886BDF39CB4ED72)
{
printf("flag is %lld\n", i);
return;
}
}
}
int main()
{
HINSTANCE hdll;
hdll = LoadLibrary(TEXT("D:\\C++\\reverse.dll"));
if (hdll == NULL)
{
printf("Load dll Error: %dn", GetLastError());
return 0;
}
printf("Dll base is %llx\n", hdll);
func = ((f)((char*)hdll + 0x17A0));
len();
hash();
}
/*
Dll base is 7ffb57d20000
Len is 10
flag is 9352641078
*/
大概跑5分钟的样子
flag
hxb2018{9352641078}
[XCTF2017]first
ida64打开,主函数分析如下
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__useconds_t *v3; // rbp
unsigned int v4; // eax
int *v5; // rcx
int v6; // edx
unsigned int v7; // eax
signed __int64 v8; // rcx
__int64 v9; // rax
char v10; // bl
char v11; // dl
void (**v12)(void *); // rbp
char *v13; // r12
pthread_t *v14; // r13
void (*v15)(void *); // rdi
unsigned __int64 i; // rcx
char v17; // al
int *v18; // rdx
int v19; // esi
unsigned int v20; // eax
unsigned __int64 v21; // rdx
char *v22; // rax
char *v23; // rdx
char v24; // di
v3 = useconds;
v4 = time(0LL);
srand(v4);
do
*v3++ = 100 * (rand() % 1000);
while ( v3 != (__useconds_t *)&unk_602208 ); // 随机生成某个数
__isoc99_scanf("%63s", dword_602180);
v5 = dword_602180;
do
{
v6 = *v5++;
v7 = ~v6 & (v6 - 16843009) & 0x80808080;
}
while ( !v7 );
if ( (~v6 & (v6 - 16843009) & 0x8080) == 0 )
v7 >>= 16;
if ( (~v6 & (v6 - 16843009) & 0x8080) == 0 )
v5 = (int *)((char *)v5 + 2);
v8 = (char *)v5 - ((char *)dword_602180 + __CFADD__((_BYTE)v7, (_BYTE)v7) + 3);
v9 = 0LL;
v10 = 0;
while ( v8 != v9 )
{
v11 = *((_BYTE *)dword_602180 + v9) + v9; // 每个字符+索引
++v9;
v10 ^= v11; // 异或
}
v12 = (void (**)(void *))&newthread;
v13 = 0LL;
v14 = &newthread;
do
{
if ( pthread_create(v14, 0LL, (void *(*)(void *))start_routine, v13) )// start_routine里有关键加密
{
perror("pthread_create");
exit(-1);
}
++v13;
++v14;
}
while ( v13 != (char *)6 ); // 创建6个进程
do
{
v15 = *v12++;
pthread_join((pthread_t)v15, 0LL);
}
while ( &free != v12 );
for ( i = 0LL; ; byte_60221F[i] = v10 ^ byte_6020DF[i] ^ v17 )// 和byte_6020DF以及前面用到的v10异或
// byte_6020DF为
// FE E9 F4 E2 F1 FA F4 E4 F0 E7 E4 E5 E3 F2 F5 EF E8 FF F6 F4 FD B4 A5 B2
{
v18 = dword_602180;
do
{
v19 = *v18++;
v20 = ~v19 & (v19 - 16843009) & 0x80808080;
}
while ( !v20 );
if ( (~v19 & (v19 - 16843009) & 0x8080) == 0 )
v20 >>= 16;
if ( (~v19 & (v19 - 16843009) & 0x8080) == 0 )
v18 = (int *)((char *)v18 + 2);
v21 = (char *)v18 - ((char *)dword_602180 + __CFADD__((_BYTE)v20, (_BYTE)v20) + 3);
if ( v21 <= i )
break;
v17 = *((_BYTE *)dword_602220 + i++);
}
if ( v21 )
{
if ( (unsigned __int8)(LOBYTE(dword_602220[0]) - 48) > 0x4Au )
{
LABEL_32:
puts("Badluck! There is no flag");
return 0LL;
}
v22 = (char *)dword_602220 + 1;
v23 = (char *)(v21 + 6300192);
while ( v22 != v23 )
{
v24 = *v22++;
if ( (unsigned __int8)(v24 - 48) > 0x4Au )
goto LABEL_32;
}
}
__printf_chk(1LL, "Here is the flag:%s\n", (const char *)dword_602220);// 正确输出dword_602220
return 0LL;
}
跟进一下start_routine
sub_400E10里findcrypt插件有识别到md5的标志数组
那我们可以先爆破出来传入的数据得到juhuhfenlapsiuerhjifdunu
from hashlib import md5
from pwn import p64
ans = [0x0F59BB02BDBB4647,0x5CFCE8EC2128ACBE,0xEF0375CA659274AD,0x27422CC18FB38643,0xA72DECA745CC3EB0,0xE8341712FE5F3CBE]
ans = [p64(i) for i in ans]
print(ans)
for i in range(97,123):
for j in range(97,123):
for k in range(97,123):
for l in range(97,123):
enc = bytes([i,j,k,l])
val = md5(enc).digest()[:8]
if val in ans:
print(enc, val, ans.index(val))
#[b'GF\xbb\xbd\x02\xbbY\x0f', b'\xbe\xac(!\xec\xe8\xfc\\', b'\xadt\x92e\xcau\x03\xef', b"C\x86\xb3\x8f\xc1,B'", b'\xb0>\xccE\xa7\xec-\xa7', b'\xbe<_\xfe\x12\x174\xe8']
# b'dunu' b'\xbe<_\xfe\x12\x174\xe8' 5
# b'hfen' b'\xbe\xac(!\xec\xe8\xfc\\' 1
# b'hjif' b'\xb0>\xccE\xa7\xec-\xa7' 4
# b'iuer' b"C\x86\xb3\x8f\xc1,B'" 3
# b'juhu' b'GF\xbb\xbd\x02\xbbY\x0f' 0
# b'laps' b'\xadt\x92e\xcau\x03\xef' 2
#juhuhfenlapsiuerhjifdunu
真实的输入顺序不确定,6组字符组合一下,爆破一下顺序
如果用juhuhfenlapsiuerhjifdunu
解出来是goodjobyougeytcnsflaj284
隐约能感觉到是最后1位和倒3位出了问题,交换一下
最后确定juhuhfenlapsdunuhjifiuer
input1 = 'juhuhfenlapsiuerhjifdunu'
check = [0xfe,0xe9,0xf4,0xe2,0xf1,0xfa,0xf4,0xe4,0xf0,0xe7,0xe4,0xe5,0xe3,0xf2,0xf5,0xef,0xe8,0xff,0xf6,0xf4,0xfd,0xb4,0xa5,0xb2]
len = 24
i = 0
v10 = 0
while(i != len):
v11 = ord(input1[i]) + i
v10 = v10 ^ v11
i = i + 1
input2 = 'juhuhfenlapsdunuhjifiuer'
flag = ''
for i in range(24):
temp = ord(input2[i]) ^ v10 ^ check[i]
flag += chr(temp)
print(flag)
#goodjobyougetthisflag233
另外也可以在linux下运行,能爆出来结果
exp
from hashlib import md5
from pwn import p64
ans = [0x0F59BB02BDBB4647,0x5CFCE8EC2128ACBE,0xEF0375CA659274AD,0x27422CC18FB38643,0xA72DECA745CC3EB0,0xE8341712FE5F3CBE]
ans = [p64(i) for i in ans]
print(ans)
for i in range(97,123):
for j in range(97,123):
for k in range(97,123):
for l in range(97,123):
enc = bytes([i,j,k,l])
val = md5(enc).digest()[:8]
if val in ans:
print(enc, val, ans.index(val))
#[b'GF\xbb\xbd\x02\xbbY\x0f', b'\xbe\xac(!\xec\xe8\xfc\\', b'\xadt\x92e\xcau\x03\xef', b"C\x86\xb3\x8f\xc1,B'", b'\xb0>\xccE\xa7\xec-\xa7', b'\xbe<_\xfe\x12\x174\xe8']
# b'dunu' b'\xbe<_\xfe\x12\x174\xe8' 5
# b'hfen' b'\xbe\xac(!\xec\xe8\xfc\\' 1
# b'hjif' b'\xb0>\xccE\xa7\xec-\xa7' 4
# b'iuer' b"C\x86\xb3\x8f\xc1,B'" 3
# b'juhu' b'GF\xbb\xbd\x02\xbbY\x0f' 0
# b'laps' b'\xadt\x92e\xcau\x03\xef' 2
#juhuhfenlapsiuerhjifdunu
input1 = 'juhuhfenlapsiuerhjifdunu'
check = [0xfe,0xe9,0xf4,0xe2,0xf1,0xfa,0xf4,0xe4,0xf0,0xe7,0xe4,0xe5,0xe3,0xf2,0xf5,0xef,0xe8,0xff,0xf6,0xf4,0xfd,0xb4,0xa5,0xb2]
len = 24
i = 0
v10 = 0
while(i != len):
v11 = ord(input1[i]) + i
v10 = v10 ^ v11
i = i + 1
input2 = 'juhuhfenlapsiuerhjifdunu'
flag = ''
for i in range(24):
temp = ord(input2[i]) ^ v10 ^ check[i]
flag += chr(temp)
print(flag)
#goodjobyougetthisflag233
flag
goodjobyougetthisflag233
[西湖论剑2019预选赛]Junk_instruction
MFC文件先打开看看,要求输入flag然后check
输入错误会弹出Error!提示
学习了一下MFC逆向,要使用XSPY
先检测一下check按钮,id=03e9
接着检测一下整个窗口
可以看到OnCommand: notifycode=0000 id=03e9,func= 0x00832420(Junk_Instruction.exe+ 0x002420 )
表示点击id=03e9即check的时候程序会跳转倒0x00832420地址的函数
ida打开定位到sub_402420
可以看到有个if判断,调用了sub_402600应该就是加密函数了,跟进一下
有点混乱应该是有花指令,返回去看汇编代码
发现有很多垃圾指令。就是先用一个call跳到下一段,没什么实际意义
全部nop
2AF0, 2CA0, 2e80这几个也有类似花指令函数同样的处理。
或者用idapython去花
from ida_bytes import get_bytes, patch_bytes
import re
addr = 0x402400
end = 0x403000
buf = get_bytes(addr, end-addr)
def handler1(s):
s = s.group(0)
print("".join(["%02x"%i for i in s]))
s = b"\x90"*len(s)
return s
p = b"\xe8\x00\x00\x00\x00.*?\xc3.*?\xc3"
buf = re.sub(p, handler1, buf, flags=re.I)
patch_bytes(addr, buf)
print("Done")
去花完sub_402600如下
char __cdecl sub_402600(int a1)
{
int v1; // ecx
const WCHAR *v2; // eax
void *v3; // eax
char v5; // [esp+8h] [ebp-4BCh]
char v6[511]; // [esp+9h] [ebp-4BBh] BYREF
int v7; // [esp+208h] [ebp-2BCh]
char *v8; // [esp+20Ch] [ebp-2B8h]
int v9; // [esp+210h] [ebp-2B4h]
size_t Count; // [esp+214h] [ebp-2B0h]
int v11; // [esp+218h] [ebp-2ACh]
size_t v12; // [esp+21Ch] [ebp-2A8h]
char *v13; // [esp+220h] [ebp-2A4h]
char *v14; // [esp+224h] [ebp-2A0h]
int v15; // [esp+228h] [ebp-29Ch]
char v16[4]; // [esp+22Ch] [ebp-298h] BYREF
char *Source; // [esp+230h] [ebp-294h]
int v18; // [esp+234h] [ebp-290h]
char v19; // [esp+238h] [ebp-28Ch]
char v20; // [esp+239h] [ebp-28Bh]
char v21; // [esp+23Ah] [ebp-28Ah]
char v22; // [esp+23Bh] [ebp-289h]
char v23; // [esp+23Ch] [ebp-288h]
char v24; // [esp+23Dh] [ebp-287h]
char v25; // [esp+23Eh] [ebp-286h]
char v26; // [esp+23Fh] [ebp-285h]
char v27; // [esp+240h] [ebp-284h]
char v28; // [esp+241h] [ebp-283h]
char v29; // [esp+242h] [ebp-282h]
char v30; // [esp+243h] [ebp-281h]
char v31; // [esp+244h] [ebp-280h]
char v32; // [esp+245h] [ebp-27Fh]
char v33; // [esp+246h] [ebp-27Eh]
char v34; // [esp+247h] [ebp-27Dh]
char v35; // [esp+248h] [ebp-27Ch]
char v36; // [esp+249h] [ebp-27Bh]
char v37; // [esp+24Ah] [ebp-27Ah]
char v38; // [esp+24Bh] [ebp-279h]
char v39; // [esp+24Ch] [ebp-278h]
char v40; // [esp+24Dh] [ebp-277h]
char v41; // [esp+24Eh] [ebp-276h]
char v42; // [esp+24Fh] [ebp-275h]
char v43; // [esp+250h] [ebp-274h]
char v44; // [esp+251h] [ebp-273h]
char v45; // [esp+252h] [ebp-272h]
char v46; // [esp+253h] [ebp-271h]
char v47; // [esp+254h] [ebp-270h]
char v48; // [esp+255h] [ebp-26Fh]
char v49; // [esp+256h] [ebp-26Eh]
char v50; // [esp+257h] [ebp-26Dh]
const char *v51; // [esp+258h] [ebp-26Ch]
char *v52; // [esp+25Ch] [ebp-268h]
int i; // [esp+260h] [ebp-264h]
char *v54; // [esp+264h] [ebp-260h]
char v55; // [esp+26Dh] [ebp-257h]
char v56; // [esp+26Eh] [ebp-256h]
char v57; // [esp+26Fh] [ebp-255h]
char v58[28]; // [esp+270h] [ebp-254h] BYREF
char v59; // [esp+28Ch] [ebp-238h] BYREF
char v60[255]; // [esp+28Dh] [ebp-237h] BYREF
char v61[256]; // [esp+38Ch] [ebp-138h] BYREF
char Destination; // [esp+48Ch] [ebp-38h] BYREF
char v63[39]; // [esp+48Dh] [ebp-37h] BYREF
int v64; // [esp+4C0h] [ebp-4h]
int savedregs; // [esp+4C4h] [ebp+0h] BYREF
v18 = v1;
v64 = 3;
v19 = 0x5B;
v20 = 0xD6;
v21 = 0xD0;
v22 = 0x26;
v23 = 0xC8;
v24 = 0xDD;
v25 = 0x19;
v26 = 0x7E;
v27 = 0x6E;
v28 = 0x3E;
v29 = 0xCB;
v30 = 0x16;
v31 = 0x91;
v32 = 0x7D;
v33 = 0xFF;
v34 = 0xAF;
v35 = 0xDD;
v36 = 0x76;
v37 = 0x64;
v38 = 0xB0;
v39 = 0xF7;
v40 = 0xE5;
v41 = 0x89;
v42 = 0x57;
v43 = 0x82;
v44 = 0x9F;
v45 = 0xC;
v46 = 0;
v47 = 0x9E;
v48 = 0xD0;
v49 = 0x45;
v50 = 0xFA;
v2 = (const WCHAR *)sub_401570(&a1);
v15 = sub_4030A0(v2);
v11 = v15;
v3 = (void *)sub_401570(v15);
sub_403000(v3);
sub_4012A0(v16);
Source = (char *)unknown_libname_1(v58);
v52 = Source;
v14 = Source + 1;
v52 += strlen(v52);
v12 = ++v52 - (Source + 1);
Count = v12;
Destination = 0;
memset(v63, 0, sizeof(v63));
strncpy(&Destination, Source, v12);
if ( sub_402AF0(&Destination) )
{
v55 = 0;
v57 = 0;
LABEL_7:
v56 = v57;
}
else
{
strcpy(v61, "qwertyuiop");
memset(&v61[11], 0, 0xF5u);
v59 = 0;
memset(v60, 0, sizeof(v60));
v5 = 0;
memset(v6, 0, sizeof(v6));
v51 = v61;
v8 = &v61[1];
v51 += strlen(v51);
v7 = ++v51 - &v61[1];
sub_402CA0(&v59, v61, v51 - &v61[1]);
v54 = &Destination;
v13 = v63;
v54 += strlen(v54);
v9 = ++v54 - v63;
sub_402E80(v18, &v59, &Destination, v54 - v63);
for ( i = 31; i >= 0; --i )
{
if ( *(&Destination + i) != *((char *)&savedregs + i + (_DWORD)&loc_4026B7 - 4204867) )
{
v57 = 0;
goto LABEL_7;
}
}
v56 = 1;
}
LOBYTE(v64) = 0;
sub_403060(v58);
v64 = -1;
sub_4012A0(&a1);
return v56;
}
sub_402CA0如下,一眼rc4
sub_402AF0如下,逆向数组操作
exp
from Crypto.Cipher import ARC4
key = b'qwertyuiop'
a = [
0x5b, 0xd6, 0xd0, 0x26, 0xc8, 0xdd, 0x19, 0x7e, 0x6e, 0x3e,
0xcb, 0x16, 0x91, 0x7d, 0xff, 0xaf, 0xdd, 0x76, 0x64, 0xb0,
0xf7, 0xe5, 0x89, 0x57, 0x82, 0x9f, 0xc, 0x0, 0x9e, 0xd0, 0x45, 0xfa]
enc = b''.join([bytes([i]) for i in a])
rc4 = ARC4.new(key)
decrypted_data = rc4.decrypt(enc)[::-1]
print(decrypted_data.decode('utf-8'))
#973387a11fa3f724d74802857d3e052f
flag
flag{973387a11fa3f724d74802857d3e052f}
本文来自博客园,作者:{Tree_24},转载请注明原文链接:{https://www.cnblogs.com/Tree-24/}