flat assembler
Message board for the users of flat assembler.

Index > Linux > BRK bug with 32-bit code (Linux kernel 4.10)

Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20421
Location: In your JS exploiting you and your system
revolution 15 Sep 2023, 15:43
I came across a minor bug with the BRK syscall in 32-bit code. In some circumstances the returned address can be above 4G, which 32-bit code can't access.

PoC
Code:
;       for A in {0..15} ; do fasm -d A=$A Linux_brk_bug.asm >/dev/null && ./Linux_brk_bug ; done

; sample output. output varies on each run
;       returned value   load address
;       000000010042b000 00000000ff000000
;       0000000100f2b000 00000000ff100000
;       000000010021b000 00000000ff200000
;       0000000100002000 00000000ff300000
;       00000000ff9ed000 00000000ff400000
;       00000001014d2000 00000000ff500000
;       0000000100065000 00000000ff600000
;       000000010155a000 00000000ff700000
;       000000010120c000 00000000ff800000
;       0000000100228000 00000000ff900000
;       00000000fff8c000 00000000ffa00000
;       0000000100924000 00000000ffb00000
;       0000000100747000 00000000ffc00000
;       000000010039d000 00000000ffd00000
;       0000000100068000 00000000ffe00000
;       000000010015d000 00000000fff00000

start = 0xff000000 + A shl 20
format elf executable at start  ; must start in 32-bit mode

STDOUT_FILENO           = 1
SYS32_brk               = 45
SYS64_write             = 1
SYS64_exit_group        = 231

segment readable writeable executable

align 16
hex_table:      db '0123456789abcdef'
far_ptr         df 0:entry_64

entry $
        mov     eax,SYS32_brk
        xor     ebx,ebx
        int     0x80
        ;value returned from BRK might be >4G
        ;switch to 64-bit mode to examine the full 64-bit value in rax
        mov     ebx,cs
        xor     ebx,0x10        ; offset is +-16
        mov     word[far_ptr + 4],bx
        jmp     fword[far_ptr]  ; jmp to  entry_64
    entry_64:
        use64
        call    print_hex16
        mov     dl,' '
        call    print_char
        mov     rax,start
        call    print_hex16
        mov     dl,10
        call    print_char
        mov     eax,SYS64_exit_group
        xor     edi,edi
        syscall

print_hex16:
        ;rax = value
        push    rbx rax rcx rdx
        mov     ecx,16
        lea     rbx,[hex_table]
    .next_nibble:
        rol     rax,4
        mov     edx,eax
        and     edx,0xf
        mov     dl,[rbx + rdx]
        call    print_char
        dec     ecx
        jnz     .next_nibble
        pop     rdx rcx rax rbx
        ret

print_char:
        ;dl = character
        push    rsi rdi rax rcx r11 rdx
        mov     rsi,rsp
        mov     edx,1
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        syscall
        pop     rdx r11 rcx rax rdi rsi
        ret    
The output prints the full returned 64-bit value which normally can't be seen in 32-bit code. So the lower 32-bits will point to some other address that is not valid.

To trigger the problem the load address needs to be very high, almost at the end of the 4G space. Then calling BRK returns a value outsde of the 4G range.

The Linux version I am using is not new. Perhaps your version doesn't have this bug.
Code:
Linux 4.10.0-42-generic     


Last edited by revolution on 19 Sep 2023, 07:32; edited 1 time in total
Post 15 Sep 2023, 15:43
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20421
Location: In your JS exploiting you and your system
revolution 16 Sep 2023, 14:04
It isn't possible to allocate memory using BRK when the load address is high. Even switching to 64-bit mode and calling the 64-bit ABI the memory address is stuck at zero bytes.
Code:
;       fasm Linux_brk_bug.asm >/dev/null && ./Linux_brk_bug

start = 0xfff00000
format elf executable at start  ; must start in 32-bit mode

STDOUT_FILENO           = 1
SYS64_brk               = 12
SYS64_write             = 1
SYS64_exit_group        = 231

segment readable writeable executable

align 16
hex_table:      db '0123456789abcdef'
entry_64_ptr    df 0:entry_64

entry $
        mov     ebx,cs
        xor     ebx,0x10        ; offset is +-16
        mov     word[entry_64_ptr + 4],bx
        jmp     [entry_64_ptr]
    entry_64:
        use64
        xor     edi,edi
        mov     eax,SYS64_brk
        syscall
        push    rax
        lea     rdi,[rax + 1 shl 16]
        mov     eax,SYS64_brk
        syscall                 ; <-- this syscall fails to allocate any memory
        call    print_hex16
        mov     dl,10
        call    print_char
        pop     rax
        call    print_hex16
        mov     dl,10
        call    print_char
        mov     eax,SYS64_exit_group
        xor     edi,edi
        syscall

print_hex16:
        ;rax = value
        push    rbx rax rcx rdx
        mov     ecx,16
        lea     rbx,[hex_table]
    .next_nibble:
        rol     rax,4
        mov     edx,eax
        and     edx,0xf
        mov     dl,[rbx + rdx]
        call    print_char
        dec     ecx
        jnz     .next_nibble
        pop     rdx rcx rax rbx
        ret

print_char:
        ;dl = character
        push    rsi rdi rax rcx r11 rdx
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        mov     rsi,rsp
        mov     edx,1
        syscall
        pop     rdx r11 rcx rax rdi rsi
        ret    
Output
Code:
0000000101633000
0000000101633000    
The address doesn't move.

So the only way to allocate memory in this situation is to use MMAP or MMAP2.
Post 16 Sep 2023, 14:04
View user's profile Send private message Visit poster's website Reply with quote
FlierMate7



Joined: 06 Sep 2023
Posts: 12
FlierMate7 20 Sep 2023, 16:02
revolution wrote:

The Linux version I am using is not new. Perhaps your version doesn't have this bug.


Same behavior reported in "5.10.16.3-microsoft-standard-WSL2".

Results:
Code:
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=0 brk32.asm > /dev/null && ./brk32
00000000ff34a000 00000000ff000000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=1 brk32.asm > /dev/null && ./brk32
00000000ff8df000 00000000ff100000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=2 brk32.asm > /dev/null && ./brk32
0000000100064000 00000000ff200000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=3 brk32.asm > /dev/null && ./brk32
0000000100965000 00000000ff300000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=4 brk32.asm > /dev/null && ./brk32
00000000ff451000 00000000ff400000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=5 brk32.asm > /dev/null && ./brk32
0000000100f8c000 00000000ff500000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=6 brk32.asm > /dev/null && ./brk32
00000000ffd52000 00000000ff600000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=7 brk32.asm > /dev/null && ./brk32
00000001012fa000 00000000ff700000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=8 brk32.asm > /dev/null && ./brk32
0000000100226000 00000000ff800000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=9 brk32.asm > /dev/null && ./brk32
000000010172c000 00000000ff900000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=10 brk32.asm > /dev/null && ./brk32
00000000ffca4000 00000000ffa00000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=11 brk32.asm > /dev/null && ./brk32
0000000100ac0000 00000000ffb00000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=12 brk32.asm > /dev/null && ./brk32
0000000100e87000 00000000ffc00000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=13 brk32.asm > /dev/null && ./brk32
00000001006ec000 00000000ffd00000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=14 brk32.asm > /dev/null && ./brk32
0000000101bf1000 00000000ffe00000
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ fasm -d A=15 brk32.asm > /dev/null && ./brk32
0000000100886000 00000000fff00000    


The 64-bit mode:
Code:
boo@DESKTOP-1V5DHQJ:/mnt/c/Users/BOO/projects$ ./brk
00000001003bd000
00000001003bd000    
Post 20 Sep 2023, 16:02
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20421
Location: In your JS exploiting you and your system
revolution 20 Sep 2023, 19:02
x32 mode. Using both the x32 and x64 syscalls give the same results. No memory for you.
Code:
false equ ; if false ; then
rept 0 { ; fi
        # dual format file run with 'sh' to make the x32 executable
        EXE_NAME="$0.x32"
        fasm "$0" "$EXE_NAME"                                                              || exit $?
        # patch byte at 0x12 (e_machine) from 0x03 (x86) to 0x3e (AMD x86-64)
        printf '>' | dd of="$EXE_NAME" count=1 bs=1 seek=18 conv=notrunc 2>/dev/null       || exit $?
        "$EXE_NAME"                                                                        || exit $?
        rm "$EXE_NAME"                                                                     || exit $?
        exit $?

} restore false

start = 0xfff00000
format elf executable at start          ; normal 32 bit elf header that needs byte 0x12 patched
use64                                   ; x32 is 64-bit mode

STDOUT_FILENO           = 1
__X32_SYSCALL_BIT       = 0x40000000
SYSx32_brk              = (__X32_SYSCALL_BIT + 12)
SYSx32_write            = (__X32_SYSCALL_BIT + 1)
SYSx32_exit_group       = (__X32_SYSCALL_BIT + 231)

segment readable writeable executable

align 16
hex_table:      db '0123456789abcdef'

entry $
        xor     edi,edi
        mov     eax,SYSx32_brk
        syscall
        push    rax
        lea     rdi,[rax + 1 shl 16]
        mov     eax,SYSx32_brk
        syscall                         ; <-- this syscall fails to allocate any memory
        push    rax
        lea     rdi,[rax + 1 shl 16]
        mov     eax,SYSx32_brk and 0xff ; try the 64-bit syscall
        syscall                         ; <-- this syscall also fails to allocate any memory
        call    print_hex16
        mov     dl,10
        call    print_char
        pop     rax
        call    print_hex16
        mov     dl,10
        call    print_char
        pop     rax
        call    print_hex16
        mov     dl,10
        call    print_char
        mov     eax,SYSx32_exit_group
        xor     edi,edi
        syscall

print_hex16:
        ;rax = value
        push    rbx rax rcx rdx
        mov     ecx,16
        lea     rbx,[hex_table]
    .next_nibble:
        rol     rax,4
        mov     edx,eax
        and     edx,0xf
        mov     dl,[rbx + rdx]
        call    print_char
        dec     ecx
        jnz     .next_nibble
        pop     rdx rcx rax rbx
        ret

print_char:
        ;dl = character
        push    rsi rdi rax rcx r11 rdx
        mov     eax,SYSx32_write
        mov     edi,STDOUT_FILENO
        mov     rsi,rsp
        mov     edx,1
        syscall
        pop     rdx r11 rcx rax rdi rsi
        ret    
Output
Code:
000000010039d000
000000010039d000
000000010039d000    
Post 20 Sep 2023, 19:02
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.