Difference between revisions of "Firmware password"

From NAS-Central Buffalo - The Linkstation Wiki
Jump to: navigation, search
(PPC asm for fun and profit (1))
 
m (Page is also valid for LSPro and LSLive)
 
(12 intermediate revisions by 8 users not shown)
Line 1: Line 1:
How to find the password for the encrypted zip containing the Firmware?
+
{{Template:Articles|Terastation|LSPro|LSLive}}
 +
 
 +
''How to find the password for the encrypted zip containing the Firmware?''
 +
 
 +
== Get started ==
  
 
* First, find out that ls_servd is responsible for decrypting.
 
* First, find out that ls_servd is responsible for decrypting.
 
    
 
    
How did i find out? Well bg told me :-)
+
How did i find out? Well [[User:bg|bg]] told me :-)
  
 
  ice:~/tera>strings ls_servd|grep unzip
 
  ice:~/tera>strings ls_servd|grep unzip
  /bin/unzip -P %s %s/%s -d %s > /dev/null 2>&1
+
  /bin/unzip -P %s %s/%s -d %s > /dev/null 2>&1
 +
 
 +
I had some hope that the password is actually contained in this binary somehow.
  
We have a high chance that the password is actually contained in this binary.
 
 
However, a brief interlude with a zipcracker and the full result of the "strings"
 
However, a brief interlude with a zipcracker and the full result of the "strings"
output doesn't find a match, so we need to dig a little bit deeper...
+
output doesn't find a match, but maybe we just need to dig a little bit deeper...
 +
 
 +
The %s indicates this is a call to sprintf(3), so we need to check the third parameter of this sprintf call.
 +
 
 +
== How about disassembling the thing? ==
  
How about disassembling the thing?
+
* We need a disassembler.
  
Okay. We need a disassembler. "objdump" usually does the trick...
+
"objdump" usually does the trick...
  
 
  ice:~/tera>objdump -d ls_servd  
 
  ice:~/tera>objdump -d ls_servd  
Line 22: Line 31:
  
 
  ice:~/tera>file ls_servd  
 
  ice:~/tera>file ls_servd  
  ls_servd: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), for GNU/Linux 2.4.17, dynamically linked (uses shared libs), stripped
+
  ls_servd: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), \
 +
  for GNU/Linux 2.4.17, dynamically linked (uses shared libs), stripped
  
 
Oh, of course. Its a PPC binary, not an x86 binary.
 
Oh, of course. Its a PPC binary, not an x86 binary.
 +
 +
* We need an ''PowerPC'' disassembler.
  
 
Some googling later, I now have an (linux) ppc-cross-objdump binary.
 
Some googling later, I now have an (linux) ppc-cross-objdump binary.
Line 31: Line 43:
 
  ice:~/tera>vim DUMP
 
  ice:~/tera>vim DUMP
  
Now we have two new problems.
+
Good. We have the code, and an hexdump in there. But now we have two more problems
  
* First, the file is big. we have about 8k lines assembler code.
+
== Understanding the code. ==
* Second, I don't know PPC assembler. Well, I know 6510 asm and some x86 asm, but the details of PPC are a mystery to me.
+
  
Nothing, a quick google couldn't fix. A PPC asm reference can be found here: http://www-aix.informatik.uni-tuebingen.de/doc_link/en_US/a_doc_lib/aixassem/alangref/toc.htm
+
* I have no PPC assembler knowledge.  
 +
Well, I know 6510 asm and some x86 asm, which helps with the general mindset, but the details of PPC are a mystery to me.
  
Be sure to also check Chapter 6: Extended mnemonics if you don't find a certain assembler mnemonic.
+
Nothing, a quick google couldn't fix. A PPC asm reference can be found here:
  
Now, for understanding the code. First, we need to find the system calls:
+
http://www-aix.informatik.uni-tuebingen.de/doc_link/en_US/a_doc_lib/aixassem/alangref/toc.htm
 +
 
 +
If you want to look up some mnemonics, be sure to also check "Chapter 6: Extended mnemonics" if you don't find your mnemonic.
 +
 
 +
* The file is big.
 +
We now have about 8k lines assembler code. Where to start?
 +
 
 +
The only "plaintext" part of the listing are the system calls.
 +
 
 +
10002fec:  48 01 a2 59    bl      1001d244 <wait3@plt>
 +
 
 +
Objdump nicely annotated them for us.  Hey, thanks :)
 +
 
 +
== Parameter passing. ==
 +
 
 +
From strings, we know that "/usr/bin/unzip" is being called, that is usually done by using the system(3) system call.
 +
Lets check for that. ls_servd uses a lot of system(3) calls, this is the first one:
  
 
  10005dec:  3c 60 10 01    lis    r3,4097
 
  10005dec:  3c 60 10 01    lis    r3,4097
Line 46: Line 74:
 
  10005df4:  48 01 72 01    bl      1001cff4 <system@plt>
 
  10005df4:  48 01 72 01    bl      1001cff4 <system@plt>
  
Cool, objdump alredy named them for us. This is a call to system(), which calls an external program. ls_servd uses a lot of system() calls.
+
system(3) only takes one argument, so we can assume that r3 is that argument. Lets see what it is:
  
Now for the parameter passing. We can assume that r3 is the parameter passed to system() which only takes one argument. Lets see what it is:
+
The first line fills the upper 16 bits of r3 with 4097 (hex 1001), resulting in r3=0x10010000 -
 +
the second line substracts 18876, resulting in r4=0x1000B644
  
The first line fills the upper 16 bits of r3 with 4097 (hex 1001), resulting in r3=0x10010000
+
We can now go and look that up in the hexdump part of the objdump output:
And the second line substracts 18876, resulting in r4=1000B644
+
 
+
You can now go and look that up in the hexdump part of the objdump output:
+
  
 
  1000b638 613d3078 25303258 0d0a0000 2f736269  a=0x%02X..../sbi
 
  1000b638 613d3078 25303258 0d0a0000 2f736269  a=0x%02X..../sbi
Line 59: Line 85:
 
   
 
   
 
Which makes the whole thing a call to /sbin/reboot. Yay!
 
Which makes the whole thing a call to /sbin/reboot. Yay!
 +
 +
== Finding the right place ==
 +
 +
We could now go, and look up all parameters to system, to find the correct one, but we can also do it the other way round:
 +
 +
1000c478 25303878 0a000000 2f62696e 2f756e7a  %08x..../bin/unz
 +
1000c488 6970202d 50202573 2025732f 2573202d  ip -P %s %s/%s -
 +
1000c498 64202573 203e202f 6465762f 6e756c6c  d %s > /dev/null
 +
 +
okay, the string starts at 0x1000C480 which makes the difference to 0x10010000 = 15232
 +
 +
Only two places refer to that string. The fist one looks like this:
 +
 +
10008c30:  48 00 01 89    bl      10008db8 <_init+0x5f70>
 +
10008c34:  7f 48 d3 78    mr      r8,r26
 +
10008c38:  7c 65 1b 78    mr      r5,r3
 +
10008c3c:  38 9e c4 80    addi    r4,r30,-15232 # unzip -p %s %s/%s -d %s
 +
10008c40:  7f 46 d3 78    mr      r6,r26
 +
10008c44:  38 f8 c3 c4    addi    r7,r24,-15420 # image.zip
 +
10008c48:  38 61 00 08    addi    r3,r1,8
 +
10008c4c:  4c c6 31 82    crclr  4*cr1+eq
 +
10008c50:  48 01 46 4d    bl      1001d29c <sprintf@plt>
 +
10008c54:  38 61 00 08    addi    r3,r1,8
 +
10008c58:  3b ff 00 01    addi    r31,r31,1
 +
10008c5c:  48 01 43 99    bl      1001cff4 <system@plt>
 +
 +
Yay, an sprintf(3) followoed by an system(). The system call parameters are numbered from r3 upwards, so the third parameter to the sprintf is r5, which is copied from r3 a few lines above. It looks like r3 might be the return value of the omnious subroutine at 0x10008db8.
 +
 +
Well the sub starts off a bit lengthy....
 +
 +
# Gen ZipPW in r3
 +
10008db8:  94 21 ff 10    stwu    r1,-240(r1)
 +
10008dbc:  3c 80 10 01    lis    r4,4097
 +
10008dc0:  93 61 00 dc    stw    r27,220(r1)
 +
10008dc4:  7c 08 02 a6    mflr    r0
 +
10008dc8:  3b 61 00 08    addi    r27,r1,8
 +
10008dcc:  93 e1 00 ec    stw    r31,236(r1)
 +
10008dd0:  38 84 c6 24    addi    r4,r4,-14812 # Binstring1 (41b)
 +
10008dd4:  90 01 00 f4    stw    r0,244(r1)
 +
10008dd8:  7c 7f 1b 78    mr      r31,r3
 +
10008ddc:  93 81 00 e0    stw    r28,224(r1)
 +
10008de0:  38 a0 00 2a    li      r5,42
 +
10008de4:  93 a1 00 e4    stw    r29,228(r1)
 +
10008de8:  7f 63 db 78    mr      r3,r27
 +
10008dec:  93 c1 00 e8    stw    r30,232(r1)
 +
10008df0:  3b 81 00 38    addi    r28,r1,56
 +
10008df4:  48 01 43 d1    bl      1001d1c4 <memcpy@plt>
 +
10008df8:  3c 80 10 01    lis    r4,4097
 +
10008dfc:  38 84 c6 4e    addi    r4,r4,-14770 # Binstring2 (41b)
 +
10008e00:  38 a0 00 2a    li      r5,42
 +
10008e04:  7f 83 e3 78    mr      r3,r28
 +
10008e08:  48 01 43 bd    bl      1001d1c4 <memcpy@plt>
 +
10008e0c:  3b a1 00 68    addi    r29,r1,104
 +
10008e10:  3c 80 10 01    lis    r4,4097
 +
10008e14:  38 84 c6 78    addi    r4,r4,-14728 # Binstring3 (41b)
 +
10008e18:  38 a0 00 2a    li      r5,42
 +
10008e1c:  7f a3 eb 78    mr      r3,r29
 +
10008e20:  48 01 43 a5    bl      1001d1c4 <memcpy@plt>
 +
10008e24:  3b c1 00 98    addi    r30,r1,152
 +
10008e28:  3c 80 10 01    lis    r4,4097
 +
10008e2c:  38 84 c6 a2    addi    r4,r4,-14686 # Binstring4 (41b)
 +
10008e30:  7f c3 f3 78    mr      r3,r30
 +
10008e34:  38 a0 00 2a    li      r5,42
 +
10008e38:  48 01 43 8d    bl      1001d1c4 <memcpy@plt>
 +
 +
which calls memcpy on four different 41 byte long nul terminated binary strings:
 +
 +
a0bdb8d5cea1e8c4bedbc1b3dfc8c9c4c5bde0d1dec1dfbcb1dec9e6c3a3bfe9dec4e5bebfc4dfa5db00
 +
d0b0d7e5dbbca0c8dfa6cea1c5c2dca5b1d7d6dadcc3bee1b2bda0b9e8b49fb2a4c0a5d2b1a2deb1b100
 +
c8e5c2b8ddb8c0dedfd4d8dfe7a5a5e3ceb3b2d3d5b4e5d5bfa3a6e0d4c5bfd7bdd7b0e4c2c8dcb0a300
 +
b8d4c8a7dedcb9e6b6dbb6dab8d1b9dca1b5b7cebcc5a3d5bbe2c7b4a7d8d4e49fd6bdc8e6b4a5c3e800
 +
 +
Well. This surely had me hooked. I had already suspected this "binary blob" to play some role :)
 +
 +
Then follows some less interesting code.
 +
 +
10008e3c:  2c 1f 00 01    cmpwi  r31,1
 +
10008e40:  41 82 00 ac    beq-    10008eec <_init+0x60a4> # core(r28)
 +
10008e44:  41 81 00 88    bgt-    10008ecc <_init+0x6084> # core(decide)
 +
10008e48:  2c 1f 00 00    cmpwi  r31,0
 +
# core(r27)
 +
10008e4c:  7f 63 db 78    mr      r3,r27
 +
10008e50:  41 82 00 30    beq-    10008e80 <_init+0x6038> # Cryptocore
 +
#
 +
10008e54:  3d 20 10 02    lis    r9,4098
 +
10008e58:  38 69 cc a8    addi    r3,r9,-13144 # 0x1001CCA8: nul bytes: "result_area"
 +
# return_after_cleanup
 +
10008e5c:  80 01 00 f4    lwz    r0,244(r1)
 +
10008e60:  83 61 00 dc    lwz    r27,220(r1)
 +
10008e64:  83 81 00 e0    lwz    r28,224(r1)
 +
10008e68:  7c 08 03 a6    mtlr    r0
 +
10008e6c:  83 a1 00 e4    lwz    r29,228(r1)
 +
10008e70:  83 c1 00 e8    lwz    r30,232(r1)
 +
10008e74:  83 e1 00 ec    lwz    r31,236(r1)
 +
10008e78:  38 21 00 f0    addi    r1,r1,240
 +
10008e7c:  4e 80 00 20    blr
 +
 +
which deals with deciding which of the 4 binstrings is actually used, and some cleanup on return. Then follows the part we have been hunting for:
 +
 +
# Crypto-core, r3 is pointer to binstring
 +
10008e80:  88 03 00 00    lbz    r0,0(r3)                # r0=r3[0]
 +
10008e84:  39 40 00 00    li      r10,0                  # r10=0
 +
10008e88:  3d 20 10 02    lis    r9,4098                # r9=0x10020000
 +
10008e8c:  2c 00 00 00    cmpwi  r0,0                    # if r0==0
 +
10008e90:  41 82 00 28    beq-    10008eb8 <_init+0x6070> # Towards "return_after_cleanup"
 +
10008e94:  7c 0b 03 78    mr      r11,r0                  # r11=r0
 +
10008e98:  39 09 cc a8    addi    r8,r9,-13144            # r8=0x1001CCA8: result_area
 +
# repeat
 +
10008e9c:  38 0b ff 91    addi    r0,r11,-111            # r0=r11-111; decrypt
 +
10008ea0:  7c 08 51 ae    stbx    r0,r8,r10              # r8[r10]=r0; store
 +
10008ea4:  39 4a 00 01    addi    r10,r10,1              # r10++
 +
10008ea8:  7c 03 50 ae    lbzx    r0,r3,r10              # r0=r3[r10]; get next
 +
10008eac:  2c 00 00 00    cmpwi  r0,0                    # if not nul byte
 +
10008eb0:  7c 0b 03 78    mr      r11,r0                  # r11=r0
 +
10008eb4:  40 82 ff e8    bne+    10008e9c <_init+0x6054> # To repeat
 +
#
 +
10008eb8:  39 29 cc a8    addi    r9,r9,-13144            # r9= result_area
 +
10008ebc:  38 00 00 00    li      r0,0
 +
10008ec0:  7c 09 51 ae    stbx    r0,r9,r10              # r9[r10]=0; nul terminate
 +
10008ec4:  7d 23 4b 78    mr      r3,r9                  # RETURN STRING!!!!
 +
10008ec8:  4b ff ff 94    b      10008e5c <_init+0x6014> # return_after_cleanup
 +
 +
Well well. how disappointing. The whole decryption is a ''bytewise decrement by 111''.
 +
 +
== The Passwords ==
 +
 +
* Decrypt them
 +
We have all ingerdients, now we need to decrypt the contained passwords. Time for a little perl...
 +
 +
#!/usr/local/bin/perl
 +
@a=qw(
 +
a0bdb8d5cea1e8c4bedbc1b3dfc8c9c4c5bde0d1dec1dfbcb1dec9e6c3a3bfe9dec4e5bebfc4dfa5db00
 +
d0b0d7e5dbbca0c8dfa6cea1c5c2dca5b1d7d6dadcc3bee1b2bda0b9e8b49fb2a4c0a5d2b1a2deb1b100
 +
c8e5c2b8ddb8c0dedfd4d8dfe7a5a5e3ceb3b2d3d5b4e5d5bfa3a6e0d4c5bfd7bdd7b0e4c2c8dcb0a300
 +
b8d4c8a7dedcb9e6b6dbb6dab8d1b9dca1b5b7cebcc5a3d5bbe2c7b4a7d8d4e49fd6bdc8e6b4a5c3e800
 +
);
 +
for (@a){
 +
  @b=unpack("C*",pack("H*",$_));
 +
  print map { $_?chr($_-111):"" } @b;
 +
  print "\n";
 +
};
 +
 +
Start it
 +
 +
ice:~tera>./crpt
 +
1NIf_2yUOlRDpYZUVNqboRpMBoZwT4PzoUvOPUp6l
 +
aAhvlM1Yp7_2VSm6BhgkmTOrCN1JyE0C5Q6cB3oBB
 +
YvSInIQopeipx66t_DCdfEvfP47qeVPhNhAuSYmA4
 +
IeY8omJwGlGkIbJm2FH_MV4fLsXE8ieu0gNYwE6Ty
 +
 +
Voila! A simple test shows, that the first password is the one actually used. The other ones might come in handy later :)<br>
 +
-- [[User:Sec|Sec]]
 +
 +
== Links ==
 +
* [[Firmware_update#Firmware_Passwords | Firmware Update]]
 +
* [[Examine ARM9 Firmware without Updating]]

Latest revision as of 19:33, 20 April 2010


How to find the password for the encrypted zip containing the Firmware?

Contents

Get started

  • First, find out that ls_servd is responsible for decrypting.

How did i find out? Well bg told me :-)

ice:~/tera>strings ls_servd|grep unzip
/bin/unzip -P %s %s/%s -d %s > /dev/null 2>&1

I had some hope that the password is actually contained in this binary somehow.

However, a brief interlude with a zipcracker and the full result of the "strings" output doesn't find a match, but maybe we just need to dig a little bit deeper...

The %s indicates this is a call to sprintf(3), so we need to check the third parameter of this sprintf call.

How about disassembling the thing?

  • We need a disassembler.

"objdump" usually does the trick...

ice:~/tera>objdump -d ls_servd 
/usr/libexec/elf/objdump: ls_servd: File format not recognized

Huh? Why this?

ice:~/tera>file ls_servd 
ls_servd: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), \
  for GNU/Linux 2.4.17, dynamically linked (uses shared libs), stripped

Oh, of course. Its a PPC binary, not an x86 binary.

  • We need an PowerPC disassembler.

Some googling later, I now have an (linux) ppc-cross-objdump binary.

ice:~/tera>./ppc-linux-objdump -s -d ls_servd >DUMP
ice:~/tera>vim DUMP

Good. We have the code, and an hexdump in there. But now we have two more problems

Understanding the code.

  • I have no PPC assembler knowledge.

Well, I know 6510 asm and some x86 asm, which helps with the general mindset, but the details of PPC are a mystery to me.

Nothing, a quick google couldn't fix. A PPC asm reference can be found here:

http://www-aix.informatik.uni-tuebingen.de/doc_link/en_US/a_doc_lib/aixassem/alangref/toc.htm

If you want to look up some mnemonics, be sure to also check "Chapter 6: Extended mnemonics" if you don't find your mnemonic.

  • The file is big.

We now have about 8k lines assembler code. Where to start?

The only "plaintext" part of the listing are the system calls.

10002fec:   48 01 a2 59     bl      1001d244 <wait3@plt>

Objdump nicely annotated them for us. Hey, thanks :)

Parameter passing.

From strings, we know that "/usr/bin/unzip" is being called, that is usually done by using the system(3) system call. Lets check for that. ls_servd uses a lot of system(3) calls, this is the first one:

10005dec:   3c 60 10 01     lis     r3,4097
10005df0:   38 63 b6 44     addi    r3,r3,-18876
10005df4:   48 01 72 01     bl      1001cff4 <system@plt>

system(3) only takes one argument, so we can assume that r3 is that argument. Lets see what it is:

The first line fills the upper 16 bits of r3 with 4097 (hex 1001), resulting in r3=0x10010000 - the second line substracts 18876, resulting in r4=0x1000B644

We can now go and look that up in the hexdump part of the objdump output:

1000b638 613d3078 25303258 0d0a0000 2f736269  a=0x%02X..../sbi
1000b648 6e2f7265 626f6f74 00000000 6c69626c  n/reboot....libl

Which makes the whole thing a call to /sbin/reboot. Yay!

Finding the right place

We could now go, and look up all parameters to system, to find the correct one, but we can also do it the other way round:

1000c478 25303878 0a000000 2f62696e 2f756e7a  %08x..../bin/unz
1000c488 6970202d 50202573 2025732f 2573202d  ip -P %s %s/%s -
1000c498 64202573 203e202f 6465762f 6e756c6c  d %s > /dev/null

okay, the string starts at 0x1000C480 which makes the difference to 0x10010000 = 15232

Only two places refer to that string. The fist one looks like this:

10008c30:   48 00 01 89     bl      10008db8 <_init+0x5f70>
10008c34:   7f 48 d3 78     mr      r8,r26
10008c38:   7c 65 1b 78     mr      r5,r3
10008c3c:   38 9e c4 80     addi    r4,r30,-15232 # unzip -p %s %s/%s -d %s
10008c40:   7f 46 d3 78     mr      r6,r26
10008c44:   38 f8 c3 c4     addi    r7,r24,-15420 # image.zip
10008c48:   38 61 00 08     addi    r3,r1,8
10008c4c:   4c c6 31 82     crclr   4*cr1+eq
10008c50:   48 01 46 4d     bl      1001d29c <sprintf@plt>
10008c54:   38 61 00 08     addi    r3,r1,8
10008c58:   3b ff 00 01     addi    r31,r31,1
10008c5c:   48 01 43 99     bl      1001cff4 <system@plt>

Yay, an sprintf(3) followoed by an system(). The system call parameters are numbered from r3 upwards, so the third parameter to the sprintf is r5, which is copied from r3 a few lines above. It looks like r3 might be the return value of the omnious subroutine at 0x10008db8.

Well the sub starts off a bit lengthy....

# Gen ZipPW in r3 
10008db8:   94 21 ff 10     stwu    r1,-240(r1)
10008dbc:   3c 80 10 01     lis     r4,4097
10008dc0:   93 61 00 dc     stw     r27,220(r1)
10008dc4:   7c 08 02 a6     mflr    r0
10008dc8:   3b 61 00 08     addi    r27,r1,8
10008dcc:   93 e1 00 ec     stw     r31,236(r1)
10008dd0:   38 84 c6 24     addi    r4,r4,-14812 # Binstring1 (41b)
10008dd4:   90 01 00 f4     stw     r0,244(r1)
10008dd8:   7c 7f 1b 78     mr      r31,r3
10008ddc:   93 81 00 e0     stw     r28,224(r1)
10008de0:   38 a0 00 2a     li      r5,42
10008de4:   93 a1 00 e4     stw     r29,228(r1)
10008de8:   7f 63 db 78     mr      r3,r27
10008dec:   93 c1 00 e8     stw     r30,232(r1)
10008df0:   3b 81 00 38     addi    r28,r1,56
10008df4:   48 01 43 d1     bl      1001d1c4 <memcpy@plt>
10008df8:   3c 80 10 01     lis     r4,4097
10008dfc:   38 84 c6 4e     addi    r4,r4,-14770 # Binstring2 (41b)
10008e00:   38 a0 00 2a     li      r5,42
10008e04:   7f 83 e3 78     mr      r3,r28
10008e08:   48 01 43 bd     bl      1001d1c4 <memcpy@plt>
10008e0c:   3b a1 00 68     addi    r29,r1,104
10008e10:   3c 80 10 01     lis     r4,4097
10008e14:   38 84 c6 78     addi    r4,r4,-14728 # Binstring3 (41b)
10008e18:   38 a0 00 2a     li      r5,42
10008e1c:   7f a3 eb 78     mr      r3,r29
10008e20:   48 01 43 a5     bl      1001d1c4 <memcpy@plt>
10008e24:   3b c1 00 98     addi    r30,r1,152
10008e28:   3c 80 10 01     lis     r4,4097
10008e2c:   38 84 c6 a2     addi    r4,r4,-14686 # Binstring4 (41b)
10008e30:   7f c3 f3 78     mr      r3,r30
10008e34:   38 a0 00 2a     li      r5,42
10008e38:   48 01 43 8d     bl      1001d1c4 <memcpy@plt>

which calls memcpy on four different 41 byte long nul terminated binary strings:

a0bdb8d5cea1e8c4bedbc1b3dfc8c9c4c5bde0d1dec1dfbcb1dec9e6c3a3bfe9dec4e5bebfc4dfa5db00
d0b0d7e5dbbca0c8dfa6cea1c5c2dca5b1d7d6dadcc3bee1b2bda0b9e8b49fb2a4c0a5d2b1a2deb1b100
c8e5c2b8ddb8c0dedfd4d8dfe7a5a5e3ceb3b2d3d5b4e5d5bfa3a6e0d4c5bfd7bdd7b0e4c2c8dcb0a300
b8d4c8a7dedcb9e6b6dbb6dab8d1b9dca1b5b7cebcc5a3d5bbe2c7b4a7d8d4e49fd6bdc8e6b4a5c3e800

Well. This surely had me hooked. I had already suspected this "binary blob" to play some role :)

Then follows some less interesting code.

10008e3c:   2c 1f 00 01     cmpwi   r31,1
10008e40:   41 82 00 ac     beq-    10008eec <_init+0x60a4> # core(r28)
10008e44:   41 81 00 88     bgt-    10008ecc <_init+0x6084> # core(decide)
10008e48:   2c 1f 00 00     cmpwi   r31,0
# core(r27)
10008e4c:   7f 63 db 78     mr      r3,r27
10008e50:   41 82 00 30     beq-    10008e80 <_init+0x6038> # Cryptocore
#
10008e54:   3d 20 10 02     lis     r9,4098
10008e58:   38 69 cc a8     addi    r3,r9,-13144 # 0x1001CCA8: nul bytes: "result_area"
# return_after_cleanup
10008e5c:   80 01 00 f4     lwz     r0,244(r1)
10008e60:   83 61 00 dc     lwz     r27,220(r1)
10008e64:   83 81 00 e0     lwz     r28,224(r1)
10008e68:   7c 08 03 a6     mtlr    r0
10008e6c:   83 a1 00 e4     lwz     r29,228(r1)
10008e70:   83 c1 00 e8     lwz     r30,232(r1)
10008e74:   83 e1 00 ec     lwz     r31,236(r1)
10008e78:   38 21 00 f0     addi    r1,r1,240
10008e7c:   4e 80 00 20     blr

which deals with deciding which of the 4 binstrings is actually used, and some cleanup on return. Then follows the part we have been hunting for:

# Crypto-core, r3 is pointer to binstring
10008e80:   88 03 00 00     lbz     r0,0(r3)                # r0=r3[0]
10008e84:   39 40 00 00     li      r10,0                   # r10=0
10008e88:   3d 20 10 02     lis     r9,4098                 # r9=0x10020000
10008e8c:   2c 00 00 00     cmpwi   r0,0                    # if r0==0
10008e90:   41 82 00 28     beq-    10008eb8 <_init+0x6070> # Towards "return_after_cleanup"
10008e94:   7c 0b 03 78     mr      r11,r0                  # r11=r0
10008e98:   39 09 cc a8     addi    r8,r9,-13144            # r8=0x1001CCA8: result_area
# repeat
10008e9c:   38 0b ff 91     addi    r0,r11,-111             # r0=r11-111; decrypt
10008ea0:   7c 08 51 ae     stbx    r0,r8,r10               # r8[r10]=r0; store
10008ea4:   39 4a 00 01     addi    r10,r10,1               # r10++
10008ea8:   7c 03 50 ae     lbzx    r0,r3,r10               # r0=r3[r10]; get next
10008eac:   2c 00 00 00     cmpwi   r0,0                    # if not nul byte
10008eb0:   7c 0b 03 78     mr      r11,r0                  # r11=r0
10008eb4:   40 82 ff e8     bne+    10008e9c <_init+0x6054> # To repeat
#
10008eb8:   39 29 cc a8     addi    r9,r9,-13144            # r9= result_area
10008ebc:   38 00 00 00     li      r0,0
10008ec0:   7c 09 51 ae     stbx    r0,r9,r10               # r9[r10]=0; nul terminate
10008ec4:   7d 23 4b 78     mr      r3,r9                   # RETURN STRING!!!!
10008ec8:   4b ff ff 94     b       10008e5c <_init+0x6014> # return_after_cleanup

Well well. how disappointing. The whole decryption is a bytewise decrement by 111.

The Passwords

  • Decrypt them

We have all ingerdients, now we need to decrypt the contained passwords. Time for a little perl...

#!/usr/local/bin/perl
@a=qw(
a0bdb8d5cea1e8c4bedbc1b3dfc8c9c4c5bde0d1dec1dfbcb1dec9e6c3a3bfe9dec4e5bebfc4dfa5db00
d0b0d7e5dbbca0c8dfa6cea1c5c2dca5b1d7d6dadcc3bee1b2bda0b9e8b49fb2a4c0a5d2b1a2deb1b100
c8e5c2b8ddb8c0dedfd4d8dfe7a5a5e3ceb3b2d3d5b4e5d5bfa3a6e0d4c5bfd7bdd7b0e4c2c8dcb0a300
b8d4c8a7dedcb9e6b6dbb6dab8d1b9dca1b5b7cebcc5a3d5bbe2c7b4a7d8d4e49fd6bdc8e6b4a5c3e800
);
for (@a){
  @b=unpack("C*",pack("H*",$_));
  print map { $_?chr($_-111):"" } @b;
  print "\n";
};

Start it

ice:~tera>./crpt 
1NIf_2yUOlRDpYZUVNqboRpMBoZwT4PzoUvOPUp6l
aAhvlM1Yp7_2VSm6BhgkmTOrCN1JyE0C5Q6cB3oBB
YvSInIQopeipx66t_DCdfEvfP47qeVPhNhAuSYmA4
IeY8omJwGlGkIbJm2FH_MV4fLsXE8ieu0gNYwE6Ty

Voila! A simple test shows, that the first password is the one actually used. The other ones might come in handy later :)
-- Sec

Links