固件逆向
https://uefi.org/specs/UEFI/2.9_A/07_Services_Boot_Services.html#id37
https://blog.wm-team.cn/index.php/archives/81/#ByteKit
One of our physical server have been hacked, we re-install the OS but there is still something there. Can you find it?
1. execute "./run_qemu.sh" and login with username root and empty password
2. after login, execute "./getflag.sh <your input>"
3. it will reboot
4. after reboot, re-login with root and empty password, execute "./getflag.sh <your input>" again, and you will get your flag.
运行两次,先启动 qemu 看看 getflag
#!/bin/bash
BYTECTF_INPUT_GUID = 93e91ed6-1a7a-46a1-b880-c5d281700ea2
BYTECTF_OUTPUT_GUID = 93e91ed6-1a7a-46a1-b880-c5c281700ea2
BYTECTF_INPUT_VAR_FILE = "/sys/firmware/efi/efivars/ByteCTFIn- $BYTECTF_INPUT_GUID "
BYTECTF_OUTPUT_VAR_FILE = "/sys/firmware/efi/efivars/ByteCTFOut- $BYTECTF_OUTPUT_GUID "
if [ " $1 " == "" ]; then
echo " $0 <your input>"
exit 1
fi
input = $1
echo "your input is $input "
if [ -f $BYTECTF_OUTPUT_VAR_FILE ]; then
flag1 = $input
flag2 = ` cat $BYTECTF_OUTPUT_VAR_FILE | base64 | cut -c -24 `
echo "ByteCTF{ $flag1$flag2 }"
chattr -i $BYTECTF_OUTPUT_VAR_FILE
rm -f $BYTECTF_OUTPUT_VAR_FILE
exit 0
fi
if [ -f $BYTECTF_INPUT_VAR_FILE ]; then
chattr -i $BYTECTF_INPUT_VAR_FILE
rm -f $BYTECTF_INPUT_VAR_FILE
fi
echo -en "\x07\x00\x00\x00 $input " | sudo tee $BYTECTF_INPUT_VAR_FILE > /dev/null
echo "system will reboot in 10 seconds"
sh -c "sleep 10; reboot" &
用 uefi_retool 提取 bios.bin
找到 ByteKitLoaderDxe
for ( k = 0i64 ; ; k = efi_status + 1 )
{
efi_status = k;
v27 = source_size;
if ( k >= ( unsigned int )source_size )
break ;
v25 = efi_status % 11 ;
* (_BYTE * )(source_buffer + efi_status) ^= * ((_BYTE * ) & keyaddr + efi_status % 11 + 12 ); // SMC
}
v32 = source_buffer;
v33 = ( unsigned int )(v27 - 4 );
v8 = - 1 ;
key1_ptr = ( unsigned __int8 * )source_buffer; // 校验
for ( i_1 = 0i64 ; i_1 < v33; ++ i_1 )
{
v21 = v8 >> 8 ;
v22 = trump [ * key1_ptr ^ ( unsigned __int8)v8];
v23 = v22 ^ (v8 >> 8 );
++ key1_ptr;
v8 = v23;
}
v24 = ~ v8;
from idc import *
from ida_64 import *
from idaapi import *
key_addr = 0x 3A20
source = 0x 3A37
source_size = 1732
# patch
# *(_BYTE *)(source_buffer + efi_status) ^= *((_BYTE *)&keyaddr + efi_status % 11 + 12);
for i in range (source_size):
# patch_byte(source+i, get_bytes(key_addr+i))
patch_byte(source + i, get_byte(source + i) ^ get_byte(key_addr + (i % 11 ) + 12 ))
# dump file
with open ( "dump.bin" , "wb" ) as f:
f.write(get_bytes(source, source_size))
用 ida 打开
kk0 = key;
do
{
kk1 = kk0[1];
kk12 = kk1 + kk0[2];
while ( kk12 > kk1 )
{
if ( kk1 >= 0 && v11 >= kk1 )
*(_BYTE *)(kk1 + buffer) ^= *(_BYTE *)kk0;
++kk1;
}
kk0 += 3;
}
key = [ 98 , 1 , 11 , 121 , 2 , 3 , 116 , 3 , 7 , 101 , 4 , 14 , 100 , 5 ,
13 , 97 , 6 , 10 , 110 , 7 , 15 , 99 , 8 , 12 , 101 , 9 , 10 ]
cipher = [ 0x 4B , 0x 27 , 0x 42 , 0x 55 , 0x 48 , 0x 6E , 0x 41 , 0x 29 , 0x 1F , 0x 5E ,
0x 04 , 0x 04 , 0x 6B , 0x 3E , 0x 57 , 0x 5F , 0x 08 , 0x 07 , 0x 5F , 0x 3A ,
0x 31 , 0x 17 , 0x 40 , 0x 30 , 0x 5F , 0x 7A , 0x 75 , 0x 67 , 0x 36 , 0x 36 ,
0x 36 , 0x 36 ]
for i in range ( 0 , len (key) - 1 , 3 ):
for j in range (key[i + 1 ], key[i + 2 ] + key[i + 1 ]):
cipher[j] ^= key[i]
print ( "" .join([ chr (c) for c in cipher]))
得到
#KEY:By71d@nnc6_Wan77_y@0_zug6666
按题目要求输入两次,得到
root@localhost:~# ./getflag.sh KEY:By71d@nnc6_Wan77_y@0_zug6666
your input is KEY:By71d@nnc6_Wan77_y@0_zug6666
ByteCTF{KEY:By71d@nnc6_Wan77_y@0_zug6666BwAAAEsnQlVIbkEpH15qamZW}