第十二届全国大学生信息安全竞赛-RE部分WP(目前前两题,待更)

35 篇文章 0 订阅
30 篇文章 1 订阅

RE2-bbvvmm


分析

拖入IDA,题目流程基本呈现,直接看到最后的check

这里即,用户名和密码都在此验证。密码最终得到的结果在ptr+25,而用户名得到的结果,像是经过一系列字符处理,最终与明文对比。这里这个明文一看非常像base64,尝试在线解base64,发现不对。经过动态调试发现是经过sub_400A6后,字符串才变为base64模样,说明在之前还有加密。base64是一种很容易理解很简单的加密,跟进去后查看函数

在这里插入图片描述

发现完全符合base64,那就是表的问题了。读代码可以知道byte_406c20就是base64的码表

在这里插入图片描述

利用找到的base64加密源码改一下表,即可解码。

这里贴出C代码

/*
 * $Id: base64.c,v 1.2 2004/02/04 02:17:32 hno Exp $
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static void base64_init(void);

static int base64_initialized = 0;
#define BASE64_VALUE_SZ 256
#define BASE64_RESULT_SZ 8192
int base64_value[BASE64_VALUE_SZ];
const char base64_code[] = "IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y";


static void base64_init(void)
{
    int i;

    for (i = 0; i < BASE64_VALUE_SZ; i++)
	base64_value[i] = -1;

    for (i = 0; i < 64; i++)
	base64_value[(int) base64_code[i]] = i;
    base64_value['='] = 0;

    base64_initialized = 1;
}

char* base64_decode(const char *p)
{
    static char result[BASE64_RESULT_SZ];
    int j;
    int c;
    long val;
    if (!p)
	return NULL;
    if (!base64_initialized)
	base64_init();
    val = c = 0;
    for (j = 0; *p && j + 4 < BASE64_RESULT_SZ; p++) {
	unsigned int k = ((unsigned char) *p) % BASE64_VALUE_SZ;
	if (base64_value[k] < 0)
	    continue;
	val <<= 6;
	val += base64_value[k];
	if (++c < 4)
	    continue;
	/* One quantum of four encoding characters/24 bit */
	result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
	result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
	result[j++] = val & 0xff;	/* Low 8 bits */
	val = c = 0;
    }
    result[j] = 0;
    return result;
}

/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
const char* base64_encode(const char *decoded_str)
{
    static char result[BASE64_RESULT_SZ];
    int bits = 0;
    int char_count = 0;
    int out_cnt = 0;
    int c;

    if (!decoded_str)
	return decoded_str;

    if (!base64_initialized)
	base64_init();

    while ((c = (unsigned char) *decoded_str++) && out_cnt < sizeof(result) - 5) {
	bits += c;
	char_count++;
	if (char_count == 3) {
	    result[out_cnt++] = base64_code[bits >> 18];
	    result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
	    result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
	    result[out_cnt++] = base64_code[bits & 0x3f];
	    bits = 0;
	    char_count = 0;
	} else {
	    bits <<= 8;
	}
    }
    if (char_count != 0) {
	bits <<= 16 - (8 * char_count);
	result[out_cnt++] = base64_code[bits >> 18];
	result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
	if (char_count == 1) {
	    result[out_cnt++] = '=';
	    result[out_cnt++] = '=';
	} else {
	    result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
	    result[out_cnt++] = '=';
	}
    }
    result[out_cnt] = '\0';	/* terminate */
    return result;
}

/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
const char* base64_encode_bin(const char *data, int len)
{
    static char result[BASE64_RESULT_SZ];
    int bits = 0;
    int char_count = 0;
    int out_cnt = 0;

    if (!data)
	return data;

    if (!base64_initialized)
	base64_init();

    while (len-- && out_cnt < sizeof(result) - 5) {
	int c = (unsigned char) *data++;
	bits += c;
	char_count++;
	if (char_count == 3) {
	    result[out_cnt++] = base64_code[bits >> 18];
	    result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
	    result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
	    result[out_cnt++] = base64_code[bits & 0x3f];
	    bits = 0;
	    char_count = 0;
	} else {
	    bits <<= 8;
	}
    }
    if (char_count != 0) {
	bits <<= 16 - (8 * char_count);
	result[out_cnt++] = base64_code[bits >> 18];
	result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
	if (char_count == 1) {
	    result[out_cnt++] = '=';
	    result[out_cnt++] = '=';
	} else {
	    result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
	    result[out_cnt++] = '=';
	}
    }
    result[out_cnt] = '\0';	/* terminate */
    return result;
}

int main()
{
	//char str_h[]="cnbragon";
	const char* str_b64;
	char* h_str;

	base64_init();
	//str_b64=base64_encode_bin(str_h,8);
	str_b64="RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=";
	h_str=base64_decode(str_b64);

	//printf("Base64_Encode(%s)\t%s\n",str_h,str_b64);
	printf("Base64_Decode(%s)\t%s\n",str_b64,h_str);
}

可以得到结果
在这里插入图片描述

这里动态调试,会发现这里的第一个用户名处理函数。会将单个字节变为两位16进制,RDI里是我输入的参数,RSI里是产生的结果。比如 1=0x31 会变为0x33与0x31

在这里插入图片描述

阅读静态代码知道这里v33是处理后的字符串,断在4018c4这个函数执行处,观察第六个参数,(当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。)

在这里插入图片描述

在这里插入图片描述

可以看到被加工处理为一些陌生字符串,跟进去查看算法。

在这里插入图片描述

后经官方提醒,涉及国密加密,github上搜索一下,发现该加密算法与sm4国密算法完全一样。两处的S盒是一样的。githubSM4

在这里插入图片描述
在这里插入图片描述

这样就好做了。加密密钥就是
在这里插入图片描述

python代码解密

from pysm4 import encrypt, decrypt
cipher_text = 0xEF468DBAF985B2509C9E200CF3525AB6
#clear_num=0x33313332333333343335333633373338
key = 0xDA98F1DA312AB753A5703A0BFD290DD6
#cipher_num = encrypt(clear_num, mk)
#print hex(cipher_num)[2:].replace('L', '')
#key = 0xDA98F1DA312AB753A5703A0BFD290DD6
plain_text = decrypt(cipher_text, key)
plain_text = hex(plain_text)[2:].replace('L', '')
print plain_text
flag =''
c=[0x62,0x61,0x64,0x72,0x65,0x72,0x31,0x32]
for i in c:
	flag+=chr(i)
print flag

得到用户名 :badrer12

接下来是密码的部分。密码涉及虚拟机,我虚拟机分析一直不太行,只会F7一直跟进每一步观察数据变化。首先找到虚拟机入口

在这里插入图片描述

我的做法比较笨,先对ptr(密码初始存在地方下硬件读断点,找到第一个调用的函数) 在这个if里的call eax下断点,当密码数据被读后,每次F7跟进eax处理,记录下跟密码所有的处理,最后得到以下几个关键地方
在这里插入图片描述

将密码第一位与0x78异或
在这里插入图片描述
比较处理长度

在这里插入图片描述

异或后的数据相加。这里由最后验证ptr+25的地址就是这里最后相加后存储的地方。反复跑几遍都断在这几个个点,可以得到逻辑。所以只要密码与0x78 0x79 0x7a 0x7b 0x7c 0x7d异或为0即可。

得到密码xyz{|}

总结

该题应该是我目前所做过的题里很难的了。对于虚拟机的处理我做的还是不好,没有学会很有效率的方式。下次尝试在GDB里对所有可能参与的内存下awatch断点,应该会比一步一步F7好做一点。毕竟关键内存就那几个。


RE1 -easygogogo


分析

该题比较简单,算是签到。使用IDA Search-sequence of byte 搜索关键字符串 Please,来到程序交互入口。紧接着慢慢调试F7 看到flag明文
在这里插入图片描述

总结

考察的是动态调试与字符串搜索,因为shift+F12找不到字符串。


比赛总结

对于我来说整个比赛难度还是很大的,RE一共6题,非elf与pe文件的我都不会。所幸是两道elf题用耐心磨出来了。队友对我提供了很大的帮助,感受到了团队的力量。以及赛后感叹,比赛只是学习的一部分,没必要因为比赛冷落了周围重要的人,重要的事。主心骨不能变。最后队伍华北地区面板排名28,不知道能不能进线下赛,随缘!

明日计划

  1. 攻防世界下一题

  2. 随时等待比赛其他几题WP出来然后复现。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值