Sunday, November 21, 2010

Root Password hacking when neither cdrom nor jumpstart available

There are many articles on web talking about "Solaris root password recovery".
Procedure followed is to boot the machine by a cdrom in single user mode, mount
the root file system and then to edit /etc/shadow file. One of my Sys Admin
friend wanted to know if there was a way to do this without cdrom and hence
this exercise of booting the machine with kmdb.
First thing I did was to boot the machine in single user mode with kmdb loaded:
ok boot kmdb -s
Resetting ...
Sun Serverblade1 (UltraSPARC-IIe 650MHz), No Keyboard
Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
OpenBoot 4.11.3, 1024 MB memory installed, Serial #52785242.
Ethernet address 0:3:ba:4d:3:74, Host ID: 8325705a.
 
 
Rebooting with command: boot kmdb -s
Boot device: /pci@1f,0/ide@d/disk@0,0:a File and args: kmdb -s
Loading kmdb...
SunOS Release 5.10 Version Generic_141444-09 64-bit
Copyright 1983-2009 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
WARNING: todblade: kernel debugger detected: hardware watchdog disabled
Booting to milestone "milestone/single-user:default".
Hostname: solarisbox
As soon as I got the hostname displayed on the console, I sent a break and
dropped into kmdb prompt.
cli>break -y s3
s3: Break sent.
cli>console -f s3
[Connected with input enabled on fru S3]
Escape Sequence is '#.'
I then added a break point at exec_common to trace the exec of sulogin process.
[0]> exec_common+0x16c:b
[0]> :c
kmdb: stop at exec_common+0x16c
kmdb: target stopped at:
exec_common+0x16c: orcc %g0, %o0, %i3
[0]> $C
000002a100728ff1 exec_common+0x16c(40e0c, 0, cdf18, 1813070, 0, 0)
000002a100729231 exece+0x10(40e0c, fd87bdf0, cdf18, b9fa8, 1010101, 80808080)
000002a1007292e1 syscall_trap32+0xcc(40e0c, fd87bdf0, cdf18, b9fa8, 1010101,
80808080)
[0]> 000002a100729231+0x7c7::print struct pathname
{
pn_buf = 0x30002b20080 "/sbin/sh"
pn_path = 0x30002b20080 "/sbin/sh"
pn_pathlen = 0x8
pn_bufsize = 0x400
}
[0]>
Above doesn't look like the one we are interested in. I put a break point at
exec_common+0x16c because, the pathname passed in from userland is pulled into
kernel land by pn_get at exec_common+0x16c. Look at following dis code.
[0]> exec_common+0x16c::dis
exec_common+0x144: ld [%g7 + 0x124], %l4
exec_common+0x148: st %l4, [%fp + 0x7eb]
exec_common+0x14c: call +0x8f724 <sigorset>
exec_common+0x150: add %g1, 0x3a8, %o1
exec_common+0x154: call -0xa6df0 <mutex_exit>
exec_common+0x158: ldx [%l1 + 0x10], %o0
exec_common+0x15c: add %fp, 0x7c7, %o2
exec_common+0x160: mov %i0, %o0
exec_common+0x164: call +0x4c130 <pn_get>
exec_common+0x168: mov %i4, %o1
exec_common+0x16c: orcc %g0, %o0, %i3
exec_common+0x170: bne,pn %icc, +0x6d8 <exec_common+0x848>
exec_common+0x174: add %fp, 0x7a7, %l7
exec_common+0x178: call +0x4c044 <pn_alloc>
exec_common+0x17c: add %fp, 0x7a7, %o0
exec_common+0x180: add %fp, 0x7c7, %o0
exec_common+0x184: add %fp, 0x7ef, %o3
exec_common+0x188: add %fp, 0x7f7, %o4
exec_common+0x18c: mov %l7, %o1
exec_common+0x190: call +0x30008 <lookuppn>
exec_common+0x194: mov 0x1, %o2
[0]>
 
I had to now step through exec_common+0x16c as shown below. I ignored around
30 exec_common calls and blindly continued as nothing was interesting and
relevant.
I was looking for "Requesting System Maintenance Mode" message to be displayed
on console. This message is displayed while sulogin process is created:

http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/svc/startd/fork.c#221
[0]> :c
Requesting System Maikmdb: stop at exec_common+0x16c
kmdb: target stopped at:
exec_common+0x16c: orcc %g0, %o0, %i3
Part of "Requesting System Maintenance Mode" message is displayed, this should
be the process of our interest.
[0]> $C
000002a100758ff1 exec_common+0x16c(38f3c, 0, ffbfff18, 1813070, 0, 0)
000002a100759231 exece+0x10(38f3c, fd07be58, ffbfff18, 7cf28, 0, ff2303a8)
000002a1007592e1 syscall_trap32+0xcc(38f3c, fd07be58, ffbfff18, 7cf28, 0,
ff2303a8)
[0]> 000002a100759231+0x7c7::print struct pathname
{
pn_buf = 0x30002b1e480 "/sbin/sulogin"
pn_path = 0x30002b1e480 "/sbin/sulogin"
pn_pathlen = 0xd
pn_bufsize = 0x400
}
 
Yes, indeed this is the process of our interest. sulogin will later read in
/etc/shadow file for root entry. It is better to track all UFS file systems
read function from now on and to look out for /etc/shadow file.
[0]> ufs_read+8:b
[0]> :c
ntenkmdb: stop at ufs`ufs_read+8
kmdb: target stopped at:
ufs`ufs_read+8: clr %l0
I stepped through uninteresting files. After reading /etc/default/login and
/etc/nsswitch.conf file, sulogin opens /etc/shadow file.
[0]> $c
ufs`ufs_read+8(30003c2ca00, 2a100759a10, 0, 300004d1d98, 0, ff3f6ae8)
fop_read+0x20(30003c2ca00, 2a100759a10, 0, 300004d1d98, 0, 135b98c)
read+0x274(101, 0, 30001d3da48, 400, 2001, 0)
syscall_trap32+0xcc(101, 261a0, 400, 0, ff3f4910, 821)
[0]> 30003c2ca00::print vnode_t v_path
v_path = 0x30001864908 "/etc/shadow"
[0]> ::pgrep sulogin
S PID PPID PGID SID UID FLAGS ADDR NAME
R 139 7 139 139 0 0x4a004000 00000300002df858 sulogin
[0]> 00000300002df858::pfiles
FD TYPE VNODE INFO
0 CHR 000003000280edc0 /devices/pseudo/cn@0:console
1 CHR 000003000280edc0 /devices/pseudo/cn@0:console
2 CHR 000003000280edc0 /devices/pseudo/cn@0:console
3 CHR 0000030003c2d200 /devices/pseudo/sysmsg@0:sysmsg
256 REG 0000030003c2ca00 /etc/shadow
257 REG 0000030003c2ca00 /etc/shadow
I then put a break point at uiomove+8. Once the data is read into memory, UFS
uses uiomove to copy read in data from kernel land to user land.
[0]> uiomove+8:b
[0]> :c
kmdb: stop at uiomove+8
kmdb: target stopped at:
uiomove+8: be,pn %xcc, +0x13c <uiomove+0x144>
[0]> $c
uiomove+8(fffffa003a6e0000, 15f, 0, 2a100759a10, fffffa003a6e0000, 15f)
vpm_data_copy+0x100(30003c2ca00, 0, 15f, 2a100759a10, 109a358, 15f)
ufs`rdip+0x468(0, 1fff, ffffffffffffe000, 186a060, 30003c6b720, 18ffd58)
ufs`ufs_read+0x208(30003c6b800, 2a100759a10, 0, 300004d1d98, 30003c6b800,
300000a1a80)
fop_read+0x20(30003c2ca00, 2a100759a10, 0, 300004d1d98, 0, 135b98c)
read+0x274(101, 0, 30001d3da48, 400, 2001, 0)
syscall_trap32+0xcc(101, 261a0, 400, 0, ff3f4910, 821)
[0]> fffffa003a6e0000 \s
0xfffffa003a6e0000: root:wqXY4dQaZCTfs:6445::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
lp:NP:6445::::::
uucp:NP:6445::::::
nuucp:NP:6445::::::
smmsp:NP:6445::::::
listen:*LK*:::::::
gdm:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
[0]>
The idea is to modify read in data in memory and have encrypted password for
root removed.
[0]> fffffa003a6e0005 \v 3a
0xfffffa003a6e0005: 0x77 = 0x3a
[0]> fffffa003a6e0006 \v 36
0xfffffa003a6e0006: 0x71 = 0x36
[0]> fffffa003a6e0007 \v 34
0xfffffa003a6e0007: 0x58 = 0x34
[0]> fffffa003a6e0008 \v 34
0xfffffa003a6e0008: 0x59 = 0x34
[0]> fffffa003a6e0009 \v 35
0xfffffa003a6e0009: 0x34 = 0x35
[0]> fffffa003a6e000a \v 3a
0xfffffa003a6e000a: 0x64 = 0x3a
[0]> fffffa003a6e000b \v 3a
0xfffffa003a6e000b: 0x51 = 0x3a
[0]> fffffa003a6e000c \v 3a
0xfffffa003a6e000c: 0x61 = 0x3a
[0]> fffffa003a6e000d \v 3a
0xfffffa003a6e000d: 0x5a = 0x3a
[0]> fffffa003a6e000e \v 3a
0xfffffa003a6e000e: 0x43 = 0x3a
[0]> fffffa003a6e000f \v 3a
0xfffffa003a6e000f: 0x54 = 0x3a
[0]> fffffa003a6e0010 \v d
0xfffffa003a6e0010: 0x66 = 0xd
[0]> fffffa003a6e0000 \s
s:14761:::::: root::6445::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
lp:NP:6445::::::
uucp:NP:6445::::::
nuucp:NP:6445::::::
smmsp:NP:6445::::::
listen:*LK*:::::::
gdm:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
[0]>
Once this was done, I removed all break points and continued boot process. Now
the root entry without password is copied from kernel land to user land.
[0]> :z
[0]> :c
Root password for system maintenance (control-d to bypass):
single-user privilege assigned to /dev/console.
Entering System Maintenance Mode
 
<root>#
At "Root password" prompt, I had to hit "Enter" key to login.
We can also get to cached file data using Virtual vnode and page structures.
[0]> 30003c6b800::print vnode_t v_pages | ::print page_t p_pagenum
p_pagenum = 0x1f974
[0]> _pagesize::print
0x2000
[0]> 0x1f974 * 0x2000 \s
0x3f2e8000: root:wqXY4dQaZCTfs:6445::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
lp:NP:6445::::::
uucp:NP:6445::::::
nuucp:NP:6445::::::
smmsp:NP:6445::::::
listen:*LK*:::::::
gdm:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
[0]>
We could have then gone about modifying addresses from 0x3f2e8005 to 0x3f2e8010
to get the same result.
After logging into the system, dumped the contents of /etc/shadow:
<root># cat /etc/shadow
s:14761:::::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
lp:NP:6445::::::
uucp:NP:6445::::::
nuucp:NP:6445::::::
smmsp:NP:6445::::::
listen:*LK*:::::::
gdm:*LK*:::::::
webservd:*LK*:::::::
postgres:NP:::::::
svctag:*LK*:6445::::::
nobody:*LK*:6445::::::
noaccess:*LK*:6445::::::
nobody4:*LK*:6445::::::
 
Even though cat shows the content of /etc/shadow as modified, this modification
has happened only in cache (kernel memory). Opening /etc/shadow file in vi shows
something like below:
<snip>
root::6445::::::^Ms:14761::::::
daemon:NP:6445::::::
bin:NP:6445::::::
<snip>
Edit the first line and remove "^Ms:14761::::::".
Rebooting the machine now will not prompt for root password until a new password
is set.

No comments:

Post a Comment