---
# System prepended metadata

title: Hackme Write-up
tags: [CTF]

---

---
title: Hackme Write-up
wargame_site: https://hackme.inndy.tw
tags: CTF
lang: zh_tw
---

# Hackme Write-up
[TOC]

## Reverse
### helloworld
是一個 ELF32
放到 linux 上跑後，直覺猜只是一個猜數字的程式
應該猜對就噴 flag 出來

簡單用 strings 查看會不會直接有 flag，並沒有

用 radare2 打開看看
```
# 用 radare2 打開
r2 helloworld
# 分析一下
[0x08048370]> aa
# 跳到 main
[0x08048370]> s main
# 反組譯這個 function
[0x0804846b]> pdf
```
![](https://i.imgur.com/1nkPGbP.jpg)
可以看到在 0x080484dd 的 jne 會跳到輸出 "Try Hard." 的部分
在這個條件判斷的再前面一點應該會有什麼 cmp
果然就在正上方有一個 `cmp eax, 0x12b9b0a1`
再往前追 eax 是啥
就會找到正上方一行 `mov eax, dword [var_10h]`
再找 var_10h 的值會被什麼決定

![](https://i.imgur.com/OcmoKNC.png)
有個 scanf
第一個參數是 0x80485e7
```
# 到 0x80485e7
[0x0804846b]> s 0x80485e7
# 看一下字串
[0x080485e7]> ps
%d
```
第二個參數是 eax, 而前面的 `lea eax, [var_10h]` 讓 eax 等於 var_10h

所以現在得知 eax 就是我們輸入的 int 數字
0x12b9b0a1 = 314159265

輸入這數字就解會輸出 flag 囉

### simple
是一個 ELF32
執行完後，大概知道要輸入完全正確的 flag
那就找找比較輸入與正確解答的部分在哪
就可以找到正確解答

用 radare2 打開看看
```
# 用 radare2 打開
r2 simple-rev
# 分析一下
[0x080483b0]> aa
# 跳到 main
[0x080484ab]> s main
# 反組譯這個 function
[0x080484ab]> pdf
```
![](https://i.imgur.com/JNbBEtq.jpg)
最下面可以看到輸出 flag 的區段
var_4ch 會放 flag

往前找 var_4ch 的值是啥
![](https://i.imgur.com/LdmBpx2.png)
結果原來是輸入的東西，沒這麼簡單
這裡還得知 輸入最長是 63 個字

回到輸出 flag 的區段
往前看要怎樣才能進這個區段
![](https://i.imgur.com/tg9EdrE.png)
比較在 var_8ch 的字串跟 `UIJT.JT.ZPVS.GMBH` 要一樣才會進

再往前看 var_8ch 的字串是啥
![](https://i.imgur.com/5SkC4WD.jpg)
有往前跳的 jne，九成九是迴圈結構
一開始 `mov dword [var_ch], 0`
再來 `jmp 0x804853a`
`lea edx, [var_4ch]` 讓 edx 指向輸入字串的頭
`mov eax, dword [var_ch]` 讓 eax 等於 index
`add eax, edx` 讓 eax 指向輸入字串第 index 個字
`movzx eax, byte[eax]` 讀出第 index 個字
還不是 0，也就是字串的結尾，就 `jne 0x80484ef`

- 如果這字不是 0xa ('\n')
    將這字 +1 並存到 var_8ch + index
    ++index
- 否則
    把輸入字串的第 index 個字清空成 0
    將 var_8ch + index 也清空成 0

那只要把 `UIJT.JT.ZPVS.GMBH` 的各字元 ASCII code - 1 就是答案囉

### pyyy
載下來是一個 .pyc 檔
先把這中間碼轉回 .py

工具: https://github.com/rocky/python-uncompyle6
```
uncompyle6 pyyy.pyc > pyyy.py
```

然後裡面程式好醜
![](https://i.imgur.com/dZI7gm6.jpg)

line 21 跟 30 可以看到超恐怖的東西
後來嘗試搞懂了 line 21 的鬼之後就沒毅力再去搞懂 line 30 的了 lol
關於 line 21, 有興趣可以看 github 上的 [wtf.py](https://github.com/LJP-TW/CTF/blob/master/Hackme/Reversing/pyyy/wtf.py), 有一步步的簡單化這句鬼的過程
為此還寫了一篇 [Python WTF](https://hackmd.io/@LJP/SyGlwUxSH/edit)

總之，這是 reverse
你可以爆改程式邏輯
在 line 23 前加一句
```python
c = l
```
問題就都沒囉

### accumulator
觀察了一下
發現邏輯是將使用者輸入用 SHA-512 hash 後
分別把 HASH 跟 原輸入 丟進 function 0x004008c0

0x004008c0 是跑類似以下程式碼
```c=
static int accumulator = 0;
static int secretarray[??]; // 要比對的 array
static int index = 0;

char *input; // 要驗證的 input
int length; // 要驗證的長度

for (char *i = input; 
    (int)input != (int)input + length; 
    ++i)
{
    accumulator += (*input);
    if (secretarray[index++] != accumulator)
        // 輸ㄌ
}
// 贏ㄌ
```

secret array 位在 0x601080
![](https://i.imgur.com/hMRiPbu.png)

因為 SHA-512 是 64bytes
所以 secretarray 前 64 個元素是 for hash
剩下的元素是 for 原輸入

所以只要把原輸入的 secretarray 拿出來反推就可以推出答案嚕

### GCCC
這題後面的備註是
> Maybe you should try some z3 magic.
> 

z3 是啥?
查了一下資料, 有點類似你給一堆條件, z3 會算出一個能滿足條件的一組解出來
中國網站講 z3 是**約束求解器**, 你給他一堆**約束**, z3 能算出一組在此**約束**下的解

以下簡單截圖
![](https://i.imgur.com/DGoRXBJ.png)

安裝只要這樣就好
```
pip install z3-solver --user
```

好, 回頭看題目

這次選用的工具是 dotPeek, 可以反編 .NET framwork 的程式, 超爽der
畫面類似醬子
![](https://i.imgur.com/5SSVH2v.png)

主要 Logic 就在這裡
![](https://i.imgur.com/QixynzB.png)

要如何寫成**條件**讓 z3 求解哩?
看 [solve.py](https://github.com/LJP-TW/CTF/blob/master/Hackme/Reversing/GCCC/solve.py) ㄅ

為何 result 要訂為 33 bits 而不訂 32 bits 勒?
看 [z3tricky.py](https://github.com/LJP-TW/CTF/blob/master/Hackme/Reversing/GCCC/z3tricky.py) ㄅ
似乎最左邊的 bit 是什麼決定了 z3 中右移時要補什麼
Test1 中, 因為 a 是 32 bits, 0x80000000 最左邊 bit 是 1
右移後, 可以看到在 b 左邊補了 1 
Test2 中, 因為 c 是 33 bits, 0x80000000 最左邊 bit 是 0
右移後, 可以看到在 d 左邊補了 0

可能就是這個 ~~Bug~~Feature 影響了 [solve.py](https://github.com/LJP-TW/CTF/blob/master/Hackme/Reversing/GCCC/solve.py) 中第 21 行的 constraint

詳細 z3 怎用可以看 [z3 python API](https://z3prover.github.io/api/html/namespacez3py.html)



<style>
/* fix mathjax rwd scroll
 * #Research-direction > simple model
 */
ul > li > .mathjax {
    width: 100%;
    overflow-x: scroll;
    overflow-wrap: break-word;
    display: inline-block;
}

/* Dark mode */

/* <!-- todo: fix highlight.js blocks; some code blocks do not render correctly --> */

body {
    background-color: #23272a !important;
}

.ui-view-area {
    background: #23272a;
    color: #ddd;
}

.ui-toc-dropdown {
    background-color: #23272A;
    border: 1px solid rgba(255,255,255,.15);
    box-shadow: 0 6px 12px rgba(255,255,255,.175);
}

.ui-toc-dropdown .nav > li > a {
    color: #ccc;
}

.ui-toc-dropdown .nav > .active:focus > a,
.ui-toc-dropdown .nav > .active:hover > a,
.ui-toc-dropdown .nav > .active > a {
    color: #bbb;
}

.ui-toc .open .ui-toc-label {
    color: #777;
}

table * {
    background-color: #424242;
    color: #c0c0c0
}

button,
a {
    color: #64B5F6;
}

a:hover,
a:focus {
    color: #2196F3;
}

a.disable,
a.disable:hover {
    color: #EEEEEE;
}

/* Dark mode code block */
/* Imported from titangene/hackmd-dark-theme */

.markdown-body pre {
    background-color: #1e1e1e;
    border: 1px solid #555 !important;
    color: #dfdfdf;
    font-weight: 600;
}
.token.operator, .token.entity,
.token.url, .language-css .token.string,
.style .token.string {
    background: unset;
}

/* Dark mode alert boxes */

.alert-info {
    color: #f3fdff;
    background: #40788A;
    border-color: #2F7A95;
}

.alert-warning {
    color: #fffaf2;
    background: #936C36;
    border-color: #AE8443;
}

.alert-danger {
    color: #fff4f4;
    background: #834040;
    border-color: #8C2F2F
}

.alert-success {
    color: #F4FFF2;
    background-color: #436643;
    border-color: #358A28;
}

/* Stylized alert boxes */

.alert-danger>p::before {
    content: "❌ Dangerous\A";
}

.alert-warning>p::before {
    content: "⚠ Warning\A";
}

.alert-info>p::before {
    content: "ℹ  Information\A";
}

.alert-warning>p::before,
.alert-danger>p::before,
.alert-info>p::before {
    white-space: pre;
    font-weight: bold;
}

</style>

<style>
/*
 * Visual Studio 2015 dark style
 * Author: Nicolas LLOBERA <nllobera@gmail.com>
 */

.hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  background: #1E1E1E;
  color: #DCDCDC;
}

.hljs-keyword,
.hljs-literal,
.hljs-symbol,
.hljs-name {
  color: #569CD6;
}
.hljs-link {
  color: #569CD6;
  text-decoration: underline;
}

.hljs-built_in,
.hljs-type {
  color: #4EC9B0;
}

.hljs-number,
.hljs-class {
  color: #B8D7A3;
}

.hljs-string,
.hljs-meta-string {
  color: #D69D85;
}

.hljs-regexp,
.hljs-template-tag {
  color: #9A5334;
}

.hljs-subst,
.hljs-function,
.hljs-title,
.hljs-params,
.hljs-formula {
  color: #DCDCDC;
}

.hljs-comment,
.hljs-quote {
  color: #57A64A;
  font-style: italic;
}

.hljs-doctag {
  color: #608B4E;
}

.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
  color: #9B9B9B;
}

.hljs-variable,
.hljs-template-variable {
  color: #BD63C5;
}

.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
  color: #9CDCFE;
}

.hljs-section {
  color: gold;
}

.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: bold;
}

/*.hljs-code {
  font-family:'Monospace';
}*/

.hljs-bullet,
.hljs-selector-tag,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
  color: #D7BA7D;
}

.hljs-addition {
  background-color: #144212;
  display: inline-block;
  width: 100%;
}

.hljs-deletion {
  background-color: #600;
  display: inline-block;
  width: 100%;
}
</style>