固件逆向

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 = 0x3A20
source = 0x3A37
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 = [0x4B, 0x27, 0x42, 0x55, 0x48, 0x6E, 0x41, 0x29, 0x1F, 0x5E,
          0x04, 0x04, 0x6B, 0x3E, 0x57, 0x5F, 0x08, 0x07, 0x5F, 0x3A,
          0x31, 0x17, 0x40, 0x30, 0x5F, 0x7A, 0x75, 0x67, 0x36, 0x36,
          0x36, 0x36]
 
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}