반응형

1. 환경

  • host: macOS
  • target: ELF 32-bit LSB executable, Atmel AVR 8-bit,

2. QEMU 설치

  • brew 를 사용한 install
    • brew install qemue
  • apt 를 사용한 install
    • apt install qemu

3. AVR 바이너리(ELF) 파일 실행

4. avr-gdb 설치

  • First, make sure you have xcode command line developer tools installed with
    $ xcode-select --install
  • Then, just run the following to install the latest version of avr-gcc:
    $ brew tap osx-cross/avr
    $ brew install avr-gcc
    $ brew install avr-gdb

5. avr-gdb 를 이용한 디버깅 실행

  • avr-gdb 명령어 실행
  • user@bk-mac:~/ctf $ avr-gdb ./atme.elf GNU gdb (GDB) 10.1 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-apple-darwin20.6.0 --target=avr". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"...
  • qemu에 실행되어 있는 ELF 파일에 원격 연결
  • (gdb) target remote :1234 Remote debugging using :1234 warning: Target-supplied registers are not supported by the current architecture 0x00000000 in __vectors ()
  • 디버깅 예제

'Security > [리얼] IoT' 카테고리의 다른 글

iptime 공유기에서 펌웨어 추출하는 방법  (2) 2016.05.13
반응형

Problem

Analysis Binary (ELF)

  • INFO user@bk-mac:~/ctf $ file atme.elf
    atme.elf: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, with debug_info, not stripped

  • Analysis main()

    user@bk-mac:~/ctf $ cat dump.asm
    0x00000092 <+0>:    ldi    r24, 0xFF    ; 255
    0x00000094 <+2>:    out    PORT_A, r24    ; 26
    0x00000096 <+4>:    out    PORT_B, r24    ; 20
    0x00000098 <+6>:    out    PORT_C, r24    ; 17
    
    0x0000009a <+8>:    ldi    r24, 0x01    ; 1
    0x0000009c <+10>:    sts    0x0060, r24    ;  0x800060 <scan>
    0x000000a0 <+14>:    sts    0x00A2, r1    ;  0x8000a2 <i>
    0x000000a4 <+18>:    rjmp    .+178        ;  0x158 <main+198>
    
    0x000000a6 <+20>:    lds    r24, 0x0060    ;  0x800060 <scan>
    0x000000aa <+24>:    out    PORT_c, r24    ; 21
    
    0x000000ac <+26>:    ldi    r24, 0x01    ; 1
    0x000000ae <+28>:    out    PORT_a, r24    ; 27
    0x000000b0 <+30>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x000000b4 <+34>:    ldi    r31, 0x00    ; 0
    0x000000b6 <+36>:    subi    r30, 0x9F    ; 159
    0x000000b8 <+38>:    sbci    r31, 0xFF    ; 255
    0x000000ba <+40>:    ld    r24, Z
    0x000000bc <+42>:    out    PORT_d, r24    ; 18
    
    0x000000be <+44>:    ldi    r24, 0x02    ; 2
    0x000000c0 <+46>:    out    PORT_a, r24    ; 27
    0x000000c2 <+48>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x000000c6 <+52>:    ldi    r31, 0x00    ; 0
    0x000000c8 <+54>:    subi    r30, 0x9E    ; 158
    0x000000ca <+56>:    sbci    r31, 0xFF    ; 255
    0x000000cc <+58>:    ld    r24, Z
    0x000000ce <+60>:    out    PORT_d, r24    ; 18
    
    0x000000d0 <+62>:    ldi    r24, 0x04    ; 4
    0x000000d2 <+64>:    out    PORT_a, r24    ; 27
    0x000000d4 <+66>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x000000d8 <+70>:    ldi    r31, 0x00    ; 0
    0x000000da <+72>:    subi    r30, 0x9D    ; 157
    0x000000dc <+74>:    sbci    r31, 0xFF    ; 255
    0x000000e0 <+78>:    out    PORT_d, r24    ; 18
    
    0x000000e2 <+80>:    ldi    r24, 0x08    ; 8
    0x000000e4 <+82>:    out    PORT_a, r24    ; 27
    0x000000e6 <+84>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x000000ea <+88>:    ldi    r31, 0x00    ; 0
    0x000000ec <+90>:    subi    r30, 0x9C    ; 156
    0x000000ee <+92>:    sbci    r31, 0xFF    ; 255
    0x000000f0 <+94>:    ld    r24, Z
    0x000000f2 <+96>:    out    PORT_d, r24    ; 18
    
    0x000000f4 <+98>:    ldi    r24, 0x10    ; 16
    0x000000f6 <+100>:    out    PORT_a, r24    ; 27
    0x000000f8 <+102>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x000000fc <+106>:    ldi    r31, 0x00    ; 0
    0x000000fe <+108>:    subi    r30, 0x9B    ; 155
    0x00000100 <+110>:    sbci    r31, 0xFF    ; 255
    0x00000102 <+112>:    ld    r24, Z
    0x00000104 <+114>:    out    PORT_d, r24    ; 18
    
    0x00000106 <+116>:    ldi    r24, 0x20    ; 32
    0x00000108 <+118>:    out    PORT_a, r24    ; 27
    0x0000010a <+120>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x0000010e <+124>:    ldi    r31, 0x00    ; 0
    0x00000110 <+126>:    subi    r30, 0x9A    ; 154
    0x00000112 <+128>:    sbci    r31, 0xFF    ; 255
    0x00000114 <+130>:    ld    r24, Z
    0x00000116 <+132>:    out    PORT_d, r24    ; 18
    
    0x00000118 <+134>:    ldi    r24, 0x40    ; 64
    0x0000011a <+136>:    out    PORT_a, r24    ; 27
    0x0000011c <+138>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x00000120 <+142>:    ldi    r31, 0x00    ; 0
    0x00000122 <+144>:    subi    r30, 0x99    ; 153
    0x00000124 <+146>:    sbci    r31, 0xFF    ; 255
    0x00000126 <+148>:    ld    r24, Z
    0x00000128 <+150>:    out    PORT_d, r24    ; 18
    
    0x0000012a <+152>:    ldi    r24, 0x80    ; 128
    0x0000012c <+154>:    out    PORT_a, r24    ; 27
    0x0000012e <+156>:    lds    r30, 0x00A2    ;  0x8000a2 <i>
    0x00000132 <+160>:    ldi    r31, 0x00    ; 0
    0x00000134 <+162>:    subi    r30, 0x98    ; 152
    0x00000136 <+164>:    sbci    r31, 0xFF    ; 255
    0x00000138 <+166>:    ld    r24, Z
    0x0000013a <+168>:    out    PORT_d, r24    ; 18
    
    0x0000013c <+170>:    ldi    r24, 0x21    ; 33
    0x0000013e <+172>:    dec    r24
    0x00000140 <+174>:    brne    .-4          ;  0x13e <main+172>
    0x00000142 <+176>:    nop
    
    0x00000144 <+178>:    lds    r24, 0x0060    ;  0x800060 <scan>
    0x00000148 <+182>:    add    r24, r24
    0x0000014a <+184>:    sts    0x0060, r24    ;  0x800060 <scan>
    0x0000014e <+188>:    lds    r24, 0x00A2    ;  0x8000a2 <i>
    0x00000152 <+192>:    subi    r24, 0xF8    ; 248
    0x00000154 <+194>:    sts    0x00A2, r24    ;  0x8000a2 <i>
    
    0x00000158 <+198>:    lds    r24, 0x00A2    ;  0x8000a2 <i>
    0x0000015c <+202>:    cpi    r24, 0x41    ; 65
    0x0000015e <+204>:    brcc    .+2          ;  0x162 <main+208>
    
    0x00000160 <+206>:    rjmp    .-188        ;  0xa6 <main+20>
    0x00000162 <+208>:    rjmp    .-202        ;  0x9a <main+8>
  • Find the column for drawing on 8x8matrix

Solution Code

    user@bk-mac:~/ctf $ cat solv.c
    #include <stdio.h>

    unsigned char column[] = {
    0xC6, 0x3C, 0x18, 0, 0x7C, 0x1C, 0x3C, 0x7E,
    0xC6, 0x66, 0x38, 0, 0xC6, 0xC, 0x18, 0x7E,
    0xC6, 0x60, 0x18, 0xC6, 6, 0x7C, 0x18, 0x5A,
    0xC6, 0xF8, 0x18, 0x6C, 0x3C, 0xCC, 0x18, 0x18,
    0xC6, 0x60, 0x18, 0x38, 6, 0xCC, 0x18, 0x18,
    0xC6, 0x60, 0x18, 0x6C, 0xC6, 0xCC, 0x18, 0x18,
    0x7C, 0xF0, 0x7E, 0xC6, 0x7C, 0x76, 0x3C,0x3C,
    0, 0, 0, 0, 0, 0, 0, 0, 0};

    void print_bin( char target )
    {
             for( int i = 7; i >= 0; -- i ){
                     printf("%d", target >> i&1);
             }
    }
    int main( void )
    {
        unsigned char scan, i;

        scan = 1;
        i = 0;
        while( 1 ){
            if( i > 0x41 ){
                scan = 1;
                i = 0;
                printf("=========\n" );
            }
            else{
                for( int j = 8; j > 0; j-- ){
                    print_bin( column[i-j] );
                }
                scan += scan;
                i -= 0xf8;
                printf("\n");
            }
        }

        return 0;
    }

Flag

  • KCTF{Uf1x3dIT}
  • run solv.c
반응형

들어가기에 앞서..

해당 포스트는 MSRC(Microsoft Security Response Center) 블로그에 작성된 First Step Hyper-V Research 내용을 토대로 작성하였습니다.


Debugging Environment

1) Intro

이 글에서 작성할 환경 설정은 nested(중첩) VM을 생성하고 이 내부에서 Hyper-V guest의 하이퍼바이저와 루트 파티션의 커널을 디버깅하기 위함입니다. Hyper-V하이퍼바이저 중에서도 Type-1 방식이기 때문에 Host 에서는 커널과 하이퍼바이저를 디버깅할 수 없습니다. 이를 위해 게스트를 만들고 그 안에 Hyper-V를 활성화(nested vm)하고 모든 것을 구성하여 디버깅을 할 것입니다. 다행히도 Hyper-V는 이 방식에서 활용할 중첩 가상화를 지원합니다. 디버깅 환경은 아래 이미지와 같습니다.

Arch for degugging on hyper-v

디버깅하려는 하이퍼바이저 내부에 다른 하이퍼바이저의 게스트로 실행합니다. 간단히 말해서 L0 루트 파티션의 사용자 공간에서 L1 하이퍼바이저와 루트 파티션의 커널을 디버그합니다.

<Nested VM 용어 설명>

  • L0 = 물리적 호스트에서 실행되는 코드. 하이퍼바이저를 실행합니다.
  • L1 = L0의 하이퍼바이저 게스트. 디버그하려는 하이퍼바이저를 실행합니다.
  • L2 = L1의 하이퍼바이저 게스트.

Hyper-V 의 중첩 가상화에 대하여 좀 더 상세한 설명은 여기를 참조해주세요 :)

2) Setting for debugging

하이퍼바이저에 디버그 지원이 내장되어 있어 디버거로 Hyper-V에 연결할 수 있습니다. 활성화하려면 BCD(Boot Configuration Data) 변수에서 몇 가지 설정을 구성해야 합니다.

 

<디버깅 할 VM 설정하기>

  1. Hyper-V 가 활성화되어 있지 않다면 활성화하기(Level0)
    1. 이 문서를 참고하여 Hyper-v 활성화
    2. Host OS 재부팅하기
  2. 디버깅을 위해 새로운 guest VM을 설정하기(Level1)
    1. 여기에 설명된 대로 1세대 Windows 10 게스트를 만듭니다. (2세대 guest에서도 작동하지만 'Secure boot' 를 비활성화해야 함)
      • 참고 이미지 (nested VM)
    2. 게스트 프로세서에서 VT-x를 활성화합니다. 활성화하지 않으면 Hyper-V 플랫폼이 게스트 내부에서 실행되지 않습니다.
      (L1 Guest OS의 전원을 끄고 L0 Host에서 PowerShell(관리자 권한) 에서 활성화 가능)
      • command
        Set-VMProcessor -VMName <VMName> -ExposeVirtualizationExtensions $true​
      • 참고 이미지
    3. L1게스트 내부에서 하이퍼바이저를 디버깅할 것이므로 L1게스트 내부에서도 Hyper-V를 활성화해야 합니다( 여기에 문서화됨 ). 나중에 게스트 VM을 재부팅합니다.
    4. 이제 디버깅을 활성화하기 위해 BCD 변수를 설정해야 합니다. L1 게스트(방금 설정한 내부 OS) 내부에서 cmd.exe (관리자 권한) 에서 다음을 실행합니다. 아래와 같이 설정을 하면 부팅 후에 적용됩니다
      • command
        # 직렬 포트를 통해 Hyper-V 디버깅 활성화
        bcdedit /hypervisorsettings serial DEBUGPORT:1 BAUDRATE:115200
        bcdedit /set hypervisordebug on
        
        # Hyper-V가 부팅 시 실행되도록 활성화하고 커널을 로드
        bcdedit /set hypervisorlaunchtype auto
        
        # 다른 직렬 포트를 통해 커널 디버그 활성화
        bcdedit /dbgsettings serial DEBUGPORT:2 BAUDRATE:115200
        bcdedit /debug on
        
        # 테스트 커널 드라이버를 load 할 일이 있을 경우, 아래 기능 활성화
        bcdedit /set TESTSIGN on
      • 참고 이미지
  3. 앞서 설정한 직렬포트와 연결하기 위해서는 Level 0 VM에서 아래와 같이 셋팅한다.
    1. Level 1 VM (guestOS) 종료하기
    2. Level 1 VM 설정하기
      • Hyper-V 관리자에서 Level1 VM 오른쪽 버튼 클릭 -> [설정] -> 왼쪽 탭에서 [하드웨어] -> [COM1]을 선택
      • Named Pipe를 선택하고 "debug_kernel"로 설정
      • COM2에 대해서도 동일한 작업을 수행하고 이름을 "debug_hv"로 설정합니다.
      • 참고:  Set-VMComPort cmdlet를 사용해서도 위와 같은 설정을 할 수 있음
    3. 이제 Named Pipe 로써 “\\.\pipe\debug_hv” 와 “\\.\pipe\debug_kernel” 이 생성되었고, 각각 hypervisor와 루트 파티션(Level1 VM) 커널에 디버깅을 할 수 있게 되었다.
      • 참고 이미지
    4. Level 0 VM에서 2개의 windbg를 open하여 named pipe로 연결한다.
      • windbg 열기 -> 디버깅 시작-커널 연결 (ctrl+k)
    5. guest OS (level1 VM)을 재부팅하면 디버깅이 가능하다.
      • 참고 이미지

3) EOD (End-Of-Documentation)

여기까지 Hyper-V의 커널과 하이퍼바이저를 디버깅하기 위해서 어떻게 해야하는지 작성해보았는데요. 이 내용은 MS 내부 직원이 분석하는 방법중 하나로써 MS블로그 글에 기재가 되어 있었습니다.

블로그 글에서 이 방법뿐만 아니라 다른 방법에 대한 링크를 아래와 같이 공유가 되었으니 참고해주세요 :)

 

반응형

들어가기에 앞서..

해당 포스트는 MSRC(Microsoft Security Response Center) 블로그에 작성된 First Ttep Hyper-V Research 내용을 토대로 작성하였습니다.


가상화 Stack에 대한 간략한 소개

1) Partition

Partition은 hypervisor 위에서 실행되는 다른 VM들을 말합니다. 파티션은 Root partition(또는 부모 파티션), enlightened guest partitions, unenlightened guest partitions 와 같이 3가지 유형으로 구분되며, 이 중에서도 Root partion 은 다른 vm과 달리 host OS를 말합니다. root partition은 웹 브라우저처럼 일반적인 프로그램들을 실행할 수 있는 Windows OS 이지만 가상화 스택의 일부는 root partion kernel과 userspace에서 실행됩니다. 루트 파티션은 하이퍼바이저와 함께 작동하는 특별한 권한이 부여된 게스트 VM으로 생각할 수 있습니다.

예를 들어, Hyper-V Management Services 는 root partion 에서 실행되고 새로운 guest partion 을 생성할 수 있습니다. 다시말해 hyper call 을 이용하여 hypervisor kernel과 통신을 합니다. 통신을 하기 위해서는 더 높은 상위 API가 있는데 그 중 하나는 VMBus 입니다. VMBus는 가상화 Stack에서 가장 많이 사용하는 cross-partiion IPC 구성요소 입니다.

2) Enlightened IO

guest partition 용 가상화 기기는 Storage, Networking, Graphic 및 입력 서브 시스템에 대해 Enlightened(계몽or향상) I/O 라는 기능도 활용할 수 있습니다. Enlightened I/O는 VMBus 위에서 실행되는 통신 프로토콜(예: SCSI) 가상화에 적합한 구현입니다. 이것은 게스트가 가상화 스택을 인식하고 있기 때문에(이런 이유로 "englightened"라 칭함) 더 나은 성능과 기능을 제공하는 device emulation layer를 우회합니다. 그러나 이 기능(Enlightended IO) 을 사용하려면 게스트 VM용 특수 드라이버가 필요합니다.

Hyper-V 통합 서비스를 설치할 때 Hyper-V enlightened I/O 와 a hypervisor aware kernel 을 사용할 수 있습니다. VSC(Virtual Server Client) 드라이버를 포함하는 통합 구성 요소는 Windows 및 일반 리눅스 배포판 일부에서 하용할 수 있습니다.

3) Generation (1세대 / 2세대)

Hyper-V에서 게스트 파티션을 만들 때 "1세대" 또는 "2세대" 게스트를 선택할 수 있습니다. 두 가지 유형의 VM 간의 차이점에 대해 설명하지 않겠지만, 1세대 VM은 대부분의 게스트 운영 체제를 지원하는 반면 2세대 VM은 보다 제한된 운영 체제(대부분 64비트)를 지원한다는 점을 알아야 합니다. 이 게시물에서는 1세대 VM만 사용하겠습니다. "1세대"와 "2세대"의 차이점에 대한 자세한 설명은 여기에서 볼 수 있습니다.

4) Summary

요약하자면 일반적인 가상화 설정은 다음과 같습니다.

Root Partition Enlightened child partitions Unenlightened child partitions

Windows
Windows or Linux FreeBSD, legacy Linux ...

5) EOD

이 블로그 게시물에 대해 알아야 할 모든 것입니다. 자세한 내용은 이 프레젠테이션 또는 TLFS를 참조 하세요.

+ Recent posts