这是第七届职业技能竞赛山东省赛的一道赛题, 价值2分.
附件中有两个文件, 使用file
命令查看, secret是MIPSel指令集的ELF文件, enc是文本文件.
符号表:
objdump -T
# secret: file format elf32-little
#
# DYNAMIC SYMBOL TABLE:
# 00000714 l d .init 00000000 .init
# 00000c54 g DF .text 00000008 Base __libc_csu_fini
# 00000001 g d *ABS* 00000000 Base _DYNAMIC_LINKING
# 00010da0 g DO .data 00000004 Base king
# 00010e50 g DO .bss 00000020 Base key
# 00000a54 g DF .text 00000088 Base readkey
# 00000d10 g DO .rodata 00000004 Base _IO_stdin_used
# 00010db0 g DO .rld_map 00000000 Base __RLD_MAP
# 00000bb0 g DF .text 000000a4 Base __libc_csu_init
# 00000adc g DF .text 000000c8 Base main
# 00000910 g DF .text 00000144 Base check
# 00000714 g DF .init 00000000 Base _init
# 00000000 w D *UND* 00000000 _ITM_registerTMCloneTable
# 00000cc0 DF *UND* 00000000 GLIBC_2.7 __isoc99_scanf
# 00000000 w D *UND* 00000000 _Jv_RegisterClasses
# 00000cb0 DF *UND* 00000000 GLIBC_2.0 __libc_start_main
# 00000ca0 DF *UND* 00000000 GLIBC_2.0 strlen
# 00000c90 DF *UND* 00000000 GLIBC_2.0 exit
# 00000000 w DF *UND* 00000000 __gmon_start__
# 00000c80 DF *UND* 00000000 GLIBC_2.0 puts
# 00000c70 DF *UND* 00000000 GLIBC_2.0 fread
# 00000c60 DF *UND* 00000000 GLIBC_2.2 fopen
# 00000000 w D *UND* 00000000 _ITM_deregisterTMCloneTable
# 00000000 w DF *UND* 00000000 GLIBC_2.2 __cxa_finalize
加密过程
直接使用Ghidra加载ELF文件, 代码比较简单, 主函数如下:
undefined4 main(void) {
undefined auStack40 [32];
puts((char *)0xd50); //"Tell me my secret !!"
readkey();
__isoc99_scanf(0xd68,auStack40); //"%32s"
check(auStack40);
puts((char *)0xd70); //"Bingo!"
return 0;
}
直接定位到check
函数看看
void check(char *param_1) {
size_t sVar1;
uint local_10;
sVar1 = strlen(param_1);
if (sVar1 != 0x20) {
puts((char *)0xd20); // "Never lost yourself"
exit(0);
}
local_10 = 0;
while( true ) {
sVar1 = strlen(param_1);
if (sVar1 <= local_10) {
return;
}
if (((int)param_1[local_10] ^ king) != (int)(char)key[local_10]) break;
local_10 = local_10 + 1;
}
puts((char *)0xd34); //"Have nothing at all"
exit(0);
}
关键代码在第15行, 可以看到, 只要找到key
数组和king
变量, 再进行异或运算即可得到flag.
重新审计main
函数, 发现函数readkey
在文件中加载了key
:
void readkey(void) {
FILE *__stream;
__stream = fopen((char *)0xd4c,(char *)0xd48); //"enc", "r+"
fread(key,0x20,1,__stream);
return;
}
在Ghidra中跳转到king
地址, 得到king = 0x44
(在ida里显示的是dword_44
, 注意不要再双击它了, 双击就会跳转到0x44的地址上去)
解密
直接编写脚本解密
$key = [System.IO.File]::ReadAllBytes(".\enc");
$flag = $key | % {
$_ -bxor 0x44;
}
[System.IO.File]::WriteAllBytes("./flag.txt", $flag);
用qemu-mipsel
加载可执行文件运行一下, 输入得到的flag, 校验通过:
图中用的是docker容器, root密码是mipsel
得到flag: 845242223606e4746c757306f8563dcb
这道题还是挺简单的, 但是比赛现场由于是线下赛且不允许用自己的电脑, 当时现场的电脑里只有ida, 但是ida不支持mipsel的反汇编, 因此根本就看不懂这个程序......I am so vegetable.
另附两个mips指令集的简单资料