Firmware password
From NAS-Central Buffalo - The Linkstation Wiki
(PPC asm for fun and profit (1)) |
m (Page is also valid for LSPro and LSLive) |
||
| (12 intermediate revisions 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. | ||
| - | |||
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, | + | 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 | 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 | ||
| - | + | 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 | 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> | ||
| - | + | 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 | 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

