# Разбор тасков с форкбомбы. Часть 1 ![](https://i.imgur.com/eTGkdZy.png) Создано при поддержке [моего канала](https://t.me/lasagnahowto). Все задачи можно найти на rev-kids20.forkbomb.ru ## Lemballovo Запускаем игру и ловим непонятную ошибку: ![](https://i.imgur.com/LHKb3NF.png) Закидываем бинарь в иду и по xref-ам находим место, где вылетает ошибка: ![](https://i.imgur.com/mZeviyh.png) Патчим на ![](https://i.imgur.com/4NmXkdz.png) И, о чудо, нас ждет уже другая ошибка ![](https://i.imgur.com/AdA9yzZ.png) Запатчив игру еще пару раз подобным образом, она заработает и выдаст флаг. ![](https://i.imgur.com/cBiiNjm.png) Полный список адресов, по которым нужно запатчить: ![](https://i.imgur.com/DR4G79Q.png) ## httpsec Пропрыгав по xref-ам находим алгоритм получения флага: ```c int sub_138D() { int v1; // eax int v2; // eax char v3[136]; // [rsp+0h] [rbp-C0h] BYREF FILE *stream; // [rsp+88h] [rbp-38h] int v5; // [rsp+94h] [rbp-2Ch] char *check_st; // [rsp+98h] [rbp-28h] int i; // [rsp+A4h] [rbp-1Ch] int res; // [rsp+A8h] [rbp-18h] int v9; // [rsp+ACh] [rbp-14h] int v10; // [rsp+B0h] [rbp-10h] int v11; // [rsp+B4h] [rbp-Ch] int v12; // [rsp+B8h] [rbp-8h] int v13; // [rsp+BCh] [rbp-4h] if ( !strcmp("/", s2) && !strcmp("GET", http_method) ) { puts("HTTP/1.1 200 OK\r\n\r"); return puts("Welcome to our fast web-server\r"); } else if ( strcmp(s2, "/secret/") == 1 && !strcmp("GET", http_method) ) { check_st = get_header_content("X-Auth"); if ( check_st ) { st_len = strlen(check_st); if ( st_len == 8 ) { v13 = check_st[4] + *check_st - check_st[6]; v12 = check_st[6] + check_st[3] - check_st[2]; v11 = check_st[7] + check_st[1] - check_st[3]; v10 = check_st[2] + check_st[5] - check_st[7]; v9 = check_st[3] + check_st[1] - check_st[2]; res = 0; for ( i = 0; i <= 7; ++i ) { if ( (v12 & 1) != 0 ) { v10 -= v13; if ( (v10 & 1) != 0 ) { v11 -= v9; v2 = v12 + v13; } else { v12 -= v9; v2 = v11 + v12; } res += v2; } else { v9 -= v11; if ( (v13 & 1) != 0 ) { v13 -= v12; v1 = v10 + v9; } else { v10 -= v11; v1 = v13 + v12; } res += v1; } v13 ^= v12; v12 ^= v11; v11 ^= v10; v10 ^= v9; v9 ^= v13; } if ( res == 444 ) { stream = fopen("flag.txt", "r"); fgets(v3, 128, stream); fclose(stream); puts("HTTP/1.1 200 OK\r\n\r"); return printf("Flag: %s\r\n", v3); } } } } } ``` Попытка решить все это дело с помощью z3 не увенчалась успехом, поэтому пришлось брутить: ```python import requests,random arr = [0]*5 while True: st = [random.randint(32,126) for _ in range(8)] arr[4] = st[4] + st[0] - st[6] arr[3] = st[6] + st[3] - st[2] arr[2] = st[7] + st[1] - st[3] arr[1] = st[2] + st[5] - st[7] arr[0] = st[3] + st[1] - st[2] check_var_444 = 0 for i in range(8): if ( (arr[3] & 1) != 0 ): arr[1] -= arr[4] if ( (arr[1] & 1) != 0 ): arr[2] -= arr[0] v1 = arr[3] + arr[4] else: arr[3] -= arr[0] v1 = arr[2] + arr[3] else: arr[0] -= arr[2]; if ( (arr[4] & 1) != 0 ): arr[4] -= arr[3] v1 = arr[1] + arr[0] else: arr[1] -= arr[2]; v1 = arr[4] + arr[3] check_var_444 += v1 arr[4] ^= arr[3] arr[3] ^= arr[2] arr[2] ^= arr[1] arr[1] ^= arr[0] arr[0] ^= arr[4] if check_var_444 == 444: print(requests.get('http://109.233.56.90:11544/secret/',headers = {"X-Auth": ''.join(map(chr,st))}).content) break ``` P.S.: Нужно было сразу брутфорсить, а не загонять в z3, но я подумал, что брутить будет слишком долго. Вот так неверная оценка сложности шифрования может привести к нескольким потерянным часам. ## Gython ~~О нет голанг~~ Закидываем в иду и наслаждаемся псевдокодом. ![](https://i.imgur.com/rtR4kVr.png) Алгоритм работы бинаря прост - дропнуть `__init__.pyc` на диск и запустить ее (в агрументах при этом передается что-то похожее на ключ - `HzURFvGeN7sClEVLJDBnZVnlrTUBDw41RFefNmcB7bdfFg==`). Вытащить адрес проживания пики можно strace-ом: ![](https://i.imgur.com/aSXQAEw.png) Декомпилируем пику и получаем следующие: ```python import base64, hashlib, os, sys, urllib.request KEY = b'K[\x87\xb7\xddR\x1e\xc0I\x1d/\xa2\xea\xa4\xadGW?Z\xffN\x80k\x9d\xe1\xfc4\xffs\xb2\x86k1' def byte_xor(ba1, ba2): return bytes([_a ^ _b for _a, _b in zip(ba1, ba2)]) def encrypt(key, plaintext): while len(key) < len(plaintext): key += hashlib.sha256(key).digest() key = key[::-1] return byte_xor(key[:len(plaintext)], plaintext) def check(params): if len(params) != 1: return False else: return hashlib.sha256(encrypt(KEY, base64.b64decode(params[0]))).hexdigest() == 'fb0d5faa2b54bc25b1654a90106913bd1dd7e5a0400986f7676ec1e0afa93d71' try: if check(sys.argv[1:]): r = urllib.request.urlopen('https://forkbomb.ru/?answer=' + str(encrypt(KEY, str(os.getuid()).encode()))) with open('1.txt', 'w') as (f): f.write(r.read(1024).decode('utf-8')) except: pass with open(__file__, 'wb') as (f): f.write('') ``` В check передаются argv, то есть тот странный ключ. На этом моменте я долго тупил и не понимал куда идти дальше. Спустя пару дней решение пришло само собой: ```python encrypt(KEY, base64.b64decode('HzURFvGeN7sClEVLJDBnZVnlrTUBDw41RFefNmcB7bdfFg==')) ``` ## Speedreading Задача состоит в получении премиум доступа в приложении для Андроида. Исследование апк в jadx заводит в `com.safonov.speedreading.application.util.PremiumUtil`: ![](https://i.imgur.com/30IQ4hA.png) Видно, что уровень доступа(премиум или нет) проверяется только на клиенте, соответственно мы можем запатчить этот самый клиент. Извлечем байткод из `classes.dex`, который находится внутри апк: `apktool d ./SpeedRead.apk`. Откроем `PremiumUtil.smali` и изменим код функции `isPremiumUser` с ``` .method public isPremiumUser()Z .locals 1 .prologue .line 22 iget-boolean v0, p0, Lcom/safonov/speedreading/application/util/PremiumUtil;->premiumUser:Z return v0 .end method ``` На ``` .method public isPremiumUser()Z .locals 1 .prologue .line 22 const/4 v0, 0x1 # v0 = true return v0 .end method ``` Пересоберем приложение: `apktool b ./SpeedRead -o SpeedRead_Patched.apk` Запускаем приложение и получаем желаемое: ![](https://i.imgur.com/1rCw4Ny.png)