Skip to content

Commit

Permalink
"Hardcore" reverse (#53)
Browse files Browse the repository at this point in the history
"Hardcore" Go challenge
  • Loading branch information
AXDOOMER authored Sep 17, 2020
1 parent 2d21740 commit f9c2b5c
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 0 deletions.
63 changes: 63 additions & 0 deletions challenges/reverse/goland/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Goland

> reverse
Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)

Défi "hardcore". Ne vous sentez pas mal si vous ne le réussissez pas.

Vous devez utiliser toutes les compétences acquises durant les défis précédants et faire vos propres recherches pour le réussir.

Utilisez Ghidra... peut-être qu'un plugin supplémentaire pourrait vous aider. Il est codé dans un langage compilé qui ne respecte pas exactement les conventions d'appel de fonction.

Vous pouvez aussi utiliser IDA Free si vous êtes à l'aise avec l'assembleur x86-64 et les graphiques (Ghidra fait aussi des graphs, il y a un petit icône pour ça).

## Setup

Requirements:
- Une distribution basée sur Linux
- [Ghidra](https://ghidra-sre.org/)

# Writeup

En ligne de commande, si on exécute le commande `file` sur le binaire, on voit un `Go BuidID`. On sait que c'est un exécutable codé en langage Go. La fonction `main` sera donc `main.main`. On peut regarder cette fonction dans Ghidra, mais pour mieux comparer ce qu'on obtient au _runtime_ au _code flow_, il est mieux d'installer le plugin [https://github.com/felberj/gotools](https://github.com/felberj/gotools) qui permet à Ghidra de faire plus du sens du code.

On verra que la logique de validation est effectuée dans `main.stuff`. En examinant la fonction dans IDA Free ou Ghidra, on peut voir une variable nommée `main_gfal` être chargée dans la boucle. On peut suivre les données pointée à `dq offset unk_54E900` et on remarque déjà un pattern. La chaîne d'octets a une longeur de 49. Cette chaîne est potentiellement le flag obscurci. Notez que `gfal` sont les lettres `flag` dans le désordre.

![image](https://user-images.githubusercontent.com/6194072/93265663-ef3a5300-f776-11ea-9c1e-bd0d0c5d3b70.png)

Les octets pointés:

```
0xe6,0xf2,0x68,0xe8,0x5a,0x6e,0xd0,0xbe,0x66,0xcc,0x6e,0xbe,0x6e,0xca,0x60,0xc6,
0xbe,0xe0,0x60,0xf4,0xc6,0x66,0x6e,0x68,0xc2,0x6e,0xbe,0xc6,0x60,0xd0,0xca,0xbe,
0x66,0x6e,0xca,0x66,0xbe,0x68,0xd0,0xbe,0xd0,0xc2,0x62,0xce,0x66,0xe2,0xe0,0x6e,0xe6
```

Son adresse est chargée dans le registre `rbx` qu'on voit utilisé plus loin avec l'instruction `movzx eax, byte ptr [rbx+rsi]`. `rsi` est utilisé comme un offset (décalage) et est peut-être l'indice de la boucle qui itère sur la chaîne. Deux instruction sous `mov rbx, cs:main_gfal`, on voyait le contenu de `rdx` mis dans `rdi`. Le contenu de `rdx` était assigné trois instructions plus haut. `mov rdx, cs:qword_55AAB8` copie la valeur 0x31 (49).

Si on continue à suivre comment le flag est manipulé, on voit `movzx eax, byte ptr [rbx+rsi]` suivi de l'instruction `shr al, 1`. La comparaison qui suit mène un un retour de la fonction. La comparaison est donc potentiellement ce qui détermine que le flag entré dans le programme est le bon.

![image](https://user-images.githubusercontent.com/6194072/93266525-307f3280-f778-11ea-9f47-1b4db61105ce.png)

On peut suivre le registre `edi`/`dil`. Juste un peu plus haut, il semble y avoir un bloc de traitement qui fait une opération inconnue. Il est un peu difficile de savoir exactement ce qui se passe.

![image](https://user-images.githubusercontent.com/6194072/93266636-5573a580-f778-11ea-936a-fe524565f1c1.png)

On préférera regarder la sortie du décompilateur Ghidra pour mieux comprendre.

![Screenshot_2020-09-15_12-30-55](https://user-images.githubusercontent.com/6194072/93264186-be591e80-f774-11ea-9d64-2a4952210608.png)

On voit que ces opérations correspondent à l'algorithme [ROT13](https://fr.wikipedia.org/wiki/ROT13). Avons-nous maintenant toute l'information nécessaire pour décoder le flag?

* Nous savons qu'un `shift right` de `1` est fait sur la valeur du flag encodé.
* La valeur entrée dans le programme est passée à travers de l'algorithme ROT13.

![image](https://user-images.githubusercontent.com/6194072/93267169-39bccf00-f779-11ea-8b34-fca3a8e926cc.png)

Essayons. Utilisons CyberChef pour obtenir le flag rapidement.

![image](https://user-images.githubusercontent.com/6194072/93267395-a0da8380-f779-11ea-9e10-fbb29c00d67c.png)

Flag: `fl4g-7u_3s7_7r0p_c0mp374n7_p0ur_37r3_4u_un1t3dc7f`

Binary file added challenges/reverse/goland/boss
Binary file not shown.
63 changes: 63 additions & 0 deletions challenges/reverse/goland/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package main

import (
"fmt"
"bufio"
"os"
)

// flag: https://gchq.github.io/CyberChef/#recipe=ROT13(true,true,13)Bit_shift_left(1)To_Hex('0x%20with%20comma',0)&input=Zmw0Zy03dV8zczdfN3IwcF9jMG1wMzc0bjdfcDB1cl8zN3IzXzR1X3VuMXQzZGM3Zg
var gfal = []byte{0xe6,0xf2,0x68,0xe8,0x5a,0x6e,0xd0,0xbe,0x66,0xcc,0x6e,0xbe,0x6e,0xca,0x60,0xc6,0xbe,0xe0,0x60,0xf4,0xc6,0x66,0x6e,0x68,0xc2,0x6e,0xbe,0xc6,0x60,0xd0,0xca,0xbe,0x66,0x6e,0xca,0x66,0xbe,0x68,0xd0,0xbe,0xd0,0xc2,0x62,0xce,0x66,0xe2,0xe0,0x6e,0xe6}

// ROT13
// Le compilateur de Go l'inline dans la fonction "stuff" donc
// ça fait une fonction plus lourde à reverser :-(
func secret(b byte) byte {
if 'a' <= b && b <= 'z' {
return (b - 'a' + 13) % ('z' - 'a' + 1) + 'a'
}

return b
}

// Logique de validation
func stuff(password string) bool {
for i, rc := range password {

// convertir de rune à byte
ch := []byte(string(rc))

if i >= len(gfal) { // indice: comparaison avec la taille
return false
}

// on encore à moitié l'input dans la fonction "secret" et décode à moitié le flag
if secret(ch[0]) != gfal[i] >> 1 {
return false
}
}

if len(gfal) <= len(password) { // indice: comparaison avec la taille
return true
}

return false
}

func main() {
scanner := bufio.NewScanner(os.Stdin)

fmt.Println("Sup. Devine le flag. Donne-moi le! J'ai faim! :D")
fmt.Print("-> ")

if scanner.Scan() {
message := scanner.Text()
if stuff(message) {
fmt.Println("Like a bowss! :O")
} else {
fmt.Println("You fail it. :(")
}
} else {
fmt.Print("Say wuuuut? xD")
}
}
3 changes: 3 additions & 0 deletions challenges/reverse/goland/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
all:
go build main.go
mv main boss

0 comments on commit f9c2b5c

Please sign in to comment.