-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
"Hardcore" Go challenge
- Loading branch information
Showing
4 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
|
||
 | ||
|
||
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. | ||
|
||
 | ||
|
||
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. | ||
|
||
 | ||
|
||
On préférera regarder la sortie du décompilateur Ghidra pour mieux comprendre. | ||
|
||
 | ||
|
||
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. | ||
|
||
 | ||
|
||
Essayons. Utilisons CyberChef pour obtenir le flag rapidement. | ||
|
||
 | ||
|
||
Flag: `fl4g-7u_3s7_7r0p_c0mp374n7_p0ur_37r3_4u_un1t3dc7f` | ||
|
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
all: | ||
go build main.go | ||
mv main boss |