===================[ Vim IDDQD* ]=================== (*) IDDQD was the code that gave you "God mode" in the Doom game. Here's a log of my MDB session. The following was made with the "script giving-vim-extra-privilege.txt" command, typed before the rest. I cleaned the escape characters, which script(1) faithfully saves. I started a vim process as a regular user sergey, then tried to load "/etc/shadow". It failed with EACCESS--users are not supposed to see password hashes stored in this file. I left the vim process to sit there, and went to modify its UID in its proc_t entry. Once I rewrote its UID to 0 (that of root, the superuser), I was able to load /etc/shadow in this same process. Many actions I took are not strictly necessary; I was just reminding myself of the formats, syntax, etc. Some further hints came from http://docs.oracle.com/cd/E19253-01/816-4854/6mb1o3baf/index.html -------------------- begin script -------------------- root@openindiana:/home/sergey# mdb -k Loading modules: [ unix genunix specfs dtrace mac cpu.generic uppc pcplusmp scsi_vhci zfs sata sd ip hook neti sockfs arp usba stmf stmf_sbd lofs random idm sppp ipc ptm crypto ] > ::ps ! grep vim R 1747 1671 1747 1671 101 0x4a004000 ffffff0159fd9018 vim (I could've used "::pgrep vim") > ffffff0159fd9018 ! ::print -ta proc_t ! grep cred ffffff0159fd9038 struct cred *p_cred = 0xffffff0157992d18 > 0xffffff0157992d18::print -ta 'struct cred' ffffff0157992d18 struct cred { ffffff0157992d18 uint_t cr_ref = 0x11b6 ffffff0157992d1c uid_t cr_uid = 0x65 <<--- we'll change this to 0 (root) ffffff0157992d20 gid_t cr_gid = 0xa ffffff0157992d24 uid_t cr_ruid = 0x65 ffffff0157992d28 gid_t cr_rgid = 0xa ffffff0157992d2c uid_t cr_suid = 0x65 ffffff0157992d30 gid_t cr_sgid = 0xa ffffff0157992d34 cred_priv_t cr_priv = { ffffff0157992d34 priv_set_t [4] crprivs = [ ffffff0157992d34 priv_set_t { ffffff0157992d34 priv_chunk_t [3] pbits = [ 0x14820, 0x7100000, 0 ] }, ffffff0157992d40 priv_set_t { ffffff0157992d40 priv_chunk_t [3] pbits = [ 0x14820, 0x7100000, 0 ] }, ffffff0157992d4c priv_set_t { ffffff0157992d4c priv_chunk_t [3] pbits = [ 0x14820, 0x7100000, 0 ] }, ffffff0157992d58 priv_set_t { ffffff0157992d58 priv_chunk_t [3] pbits = [ 0xffffffff, 0xffffffff, 0xffffffff ] }, ] ffffff0157992d64 uint_t crpriv_flags = 0 >> More [, , q, n, c, a] ? > ::sizeof uid_t sizeof (uid_t) = 4 <<----- that's how long a value we need to write > ::formats ! grep write W - write default radix unsigned int (4 bytes) Z - write hexadecimal long long (8 bytes) v - write decimal signed int (1 byte) w - write default radix unsigned short (2 bytes) > !grep sergey /etc/passwd <<--- let's verify it's actually my UID sergey:x:101:10:sergey:/home/sergey:/bin/bash > ::formats !grep decimal B - hexadecimal int (1 byte) D - decimal signed int (4 bytes) E - decimal unsigned long long (8 bytes) J - hexadecimal long long (8 bytes) K - hexadecimal uintptr_t (8 bytes) U - decimal unsigned int (4 bytes) V - decimal unsigned int (1 byte) X - hexadecimal int (4 bytes) Z - write hexadecimal long long (8 bytes) d - decimal signed short (2 bytes) e - decimal signed long long (8 bytes) u - decimal unsigned short (2 bytes) v - write decimal signed int (1 byte) x - hexadecimal short (2 bytes) > 0x65=D 101 <<----- Indeed it's my UID. > 0xffffff0157992d18::print -ta 'struct cred' !grep uid_t ffffff0157992d1c uid_t cr_uid = 0x65 ffffff0157992d24 uid_t cr_ruid = 0x65 ffffff0157992d2c uid_t cr_suid = 0x65 > ffffff0157992d1c/W 0 <<----- Now overwrite it! (with 4 bytes) mdb: failed to write 0 at address 0xffffff0157992d1c: target is not open for writing > $W <<----- Reopening kernel memory pseudo-file for writing > ffffff0157992d1c/W 0 0xffffff0157992d1c: 0x65 = 0x0 <<---- Success! Now I can open the file in vim (":r /etc/shadow" works) Best put it back when done: > ffffff0157992d1c/W 0 65 0xffffff0157992d1c: 0 = 0x65 Suggestion: Trace the "vim" process with DTrace using the FBT provider and the flowindent pragma (see examples in d/) to see how the process fails to open the /etc/shadow file, and which kernel functions are called on this logical path. Can an earlier check be subverted for the same purpose? Note: As you trace, you may want to compare arguments of syscalls or functions against known strings as a condition for tracing or skipping a call. Remember that pointers to userland C strings and D strings are very different data types! In order to access C strings passed as arguments, they need to be converted to D strings with D's built-in functions like copyinstr. See the DTrace User Guide for details, or http://docs.oracle.com/cd/E19253-01/819-5488/gcglu/index.html Caution: Remember that a typical process performs many open() system calls just to start up and load its libraries, locale info, and so on. Some of these calls may fail. So the failing open() of vim on /etc/shadow is neither the first open() nor the first failed open().