Reverse
VaultDoor-training
- 答案就寫在裡面ㄌ,他會透過
public boolean checkPassword
確認使用者輸入
VaultDoor1
- 我用sublime處理,轉C-code輸出,工人智慧也可以
VaultDoor3
- 把答案再重複做一次
1
2
3
4
5
6
7
8
9
10
11
12
13char a[] = "jU5t_a_sna_3lpm17ga45_u_4_mbrf4c"
char password[32];
for (int i = 0; i < 8; i++)
password[i] = buffer[i];
for (int i = 8; i < 16; i++)
password[i] = buffer[23-i];
for (int i = 16; i < 32; i+=2)
password[i] = buffer[46-i];
for (int i = 31; i > 16; i-=2)
password[i] = buffer[i];
for(int i = 0; i < 32; i++)
printf("%c",password[i]);
VaultDoor4
- hex,binary,octal
1
2
3
4
5
6
7
8
9
10
11int myBytes[32] = {
106 , 85 , 53 , 116 , 95 , 52 , 95 , 98 ,
0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f,
0142, 0131, 0164, 063 , 0163, 0137, 063 , 0141,
'7' , '2' , '4' , 'c' , '8' , 'f' , '9' , '2' ,
};
for(int i = 0; i < 32; i++)
printf("%c",myBytes[i]);
return 0;
VaultDoor5
- flag->url_encode->base64_encode
base64decode->url_encode->flag
source
1
JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVmJTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2JTM0JTVmJTMxJTMxJTM3JTM3JTY2JTM3JTM4JTMz
base64_decode
1 | %63%30%6e%76%33%72%74%31%6e%67%5f%66%72%30%6d%5f%62%61%35%65%5f%36%34%5f%31%31%37%37%66%37%38%33 |
- url_decode
1 | c0nv3rt1ng_fr0m_ba5e_64_1177f783 |
VaultDoor6
觀察此條件判斷,發現只要兩個相減=0就會return false
1
2
3if (((passBytes[i] ^ 0x55) - myBytes[i]) != 0) {
return false;
}因此要想辦法讓此條件=0
- 換句話說passBytes[i] ^ 0x55 = myBytes[i]
- xor性質
- A xor B = C
- A xor C = B
- 寫腳本
1
2
3
4
5
6
7
8
9int myBytes[32]= {
0x3b, 0x65, 0x21, 0xa , 0x38, 0x0 , 0x36, 0x1d,
0xa , 0x3d, 0x61, 0x27, 0x11, 0x66, 0x27, 0xa ,
0x21, 0x1d, 0x61, 0x3b, 0xa , 0x2d, 0x65, 0x27,
0xa , 0x63, 0x65, 0x64, 0x67, 0x37, 0x6d, 0x62,
};
for(int i = 0; i < 32; i++)
printf("%c",myBytes[i]^0x55);
VaultDoor7
觀察for迴圈,會發現他把hex-byte分別左移24,16,8,0
1
2
3
4
5
6for (int i=0; i<8; i++) {
x[i] = hexBytes[i*4] << 24
| hexBytes[i*4+1] << 16
| hexBytes[i*4+2] << 8
| hexBytes[i*4+3];
}將x值換成hex
1
2
3
4
5
6
7
8x[0] == 1096770097
x[1] == 1952395366
x[2] == 1600270708
x[3] == 1601398833
x[4] == 1716808014
x[5] == 1734293815
x[6] == 1667379558
x[7] == 859191138hexBytes[i*4]是左移24的結果
- hexBytes[i*4+1]是左移16的結果
- hexBytes[i*4+2]是左移8的結果
hexBytes[i*4+3]是左移24的結果
1
2
3
4
5
6
7
8x[0] = 415f6231
x[1] = 745f3066
x[2] = 5f623174
x[3] = 5f736831
x[4] = 6654694e
x[5] = 675f3937
x[6] = 63623166
x[7] = 33363762整理出來
1
0x41,0x5f,0x62,0x31,0x74,0x5f,0x30,0x66,0x5f,0x62,0x31,0x74,0x5f,0x73,0x68,0x31,0x66,0x54,0x69,0x4e,0x67,0x5f,0x39,0x37,0x63,0x62,0x31,0x66,0x33,0x36,0x37,0x62
script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22a = [
1096770097,
1952395366,
1600270708,
1601398833,
1716808014,
1734293815,
1667379558,
859191138
]
b = []
for t in a:
b.append(str(hex(t)[2::]))
flag = ""
for j in b:
for i in range(0,len(j),2):
flag += chr(int('0x'+ j[i] + j[i+1],16))
print(flag)
VaultDoor8
- 怎麼移動過來,就怎麼移動回去
1 | # |
reverse_cipher
- rev_this
1
picoCTF{w1{1wq817/gbf/g}
1 | for ( i = 0; i <= 7; ++i ) |
- script,原本-2,+5,變+2,-5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main()
{
int j;
char ptr[] = "picoCTF{w1{1wq817/gbf/g}";
for (int j = 8; j <= 22; ++j )
{
char v11 = ptr[j];
if ( j & 1 )
v11 += 2;
else
v11 -= 5;
ptr[j] = v11;
}
for(int j = 0; j <= 23; j++)
printf("%c",ptr[j]);
return 0;
}
asm1
- asm1(0x610)
asm1(0x610)
1.1
2<+3>: cmp DWORD PTR [ebp+0x8],0x3b9
<+10>: jg 0x50f <asm1+34>
2.1
2<+34>: cmp DWORD PTR [ebp+0x8],0x477
<+41>: jne 0x520 <asm1+51>
3.1
2<+51>: mov eax,DWORD PTR [ebp+0x8]
<+54>: add eax,0x11
asm2
asm2(0xc, 0x15)
1 | high_address |
1.
1 | <+6>: mov eax,DWORD PTR [ebp+0xc] |
1 | | 0x15 | <- ebp + c |
2.
1 | <+12>: mov eax,DWORD PTR [ebp+0x8] |
1 | | 0x15 | <- ebp + c |
- 檢測[ebp-0x8]
1
2<+31>: cmp DWORD PTR [ebp-0x8],0xa3d3
<+38>: jle 0x501 <asm2+20>
- 即可換成以下的script
1
2
3
4
5
6
7
8ebp_4 = 0x15
ebp_8 = 0xc
while ebp_8 <= 0xa3d3:
ebp_4 += 0x1
ebp_8 += 0xaf
print(hex(ebp_4))
asm3
intel-x86 is little endian
- e.g: 0xDEADBEEF
1
2
3
4
5
6
7
8high_address
| DE | <- 3
| AD | <- 2
| BE | <- 1
| EF | <- 0
low_address
asm3(0xc4bd37e3,0xf516e15e,0xeea4f333)
1 | high_address |
<+5>: mov ah,BYTE PTR [ebp+0x9]
eax: 00003700
<+8>: shl,0x10 左移16格
eax: 37000000
<+12>: sub al,BYTE PTR [ebp+0xd]
00-e1 = 1F
eax: 3700001F
<+15>: add ah,BYTE PTR [ebp+0xe]
- eax: 3700161F
<+18>: xor ax,WORD PTR [ebp+0x10]
161F xor f333
eax: 3700e52c
asm4(賽後解出)
- 無腦法:
寫一個c把asm4(“picoCTF_75806”)把值印出
另一組語那包也用gcc編
兩邊都生成obj檔之後,再將其兩個檔案連結
如果你是x64假夠的話,在linux需要裝1
apt-get install gcc-multilib
1 | gcc -m32 -c asm4.S -o asm4_asm.o gcc -m32 -c asm4.c -o asm4_print.o gcc -m32 -o a.out asm4_asm.o asm4_print.o ./a.out |
Time’s Up(賽後解出)
1 | from pwn import * |
Time’s Up, Again!
- ???????
Need For Speed(賽後解出)
- alarm()執行後,進程將繼續執行,在後期(alarm以後)的執行過程中將會在seconds秒後收到信號SIGALRM並執行其處理
- ida或ghidra先逆
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
- 利用GDB跳過timer設定
1
2
3
4
5
6
7
8
9
10
11
-
─────────────────────────────────────────────── Code ───────────────────────────────────────────────
0x55555555497f <main+11>: mov QWORD PTR [rbp-0x10],rsi
0x555555554983 <main+15>: mov eax,0x0
0x555555554988 <main+20>: call 0x555555554932 <header>
=> 0x55555555498d <main+25>: mov eax,0x0
0x555555554992 <main+30>: call 0x55555555487f <set_timer>
0x555555554997 <main+35>: mov eax,0x0
0x55555555499c <main+40>: call 0x5555555548d7 <get_key>
0x5555555549a1 <main+45>: mov eax,0x0
1 | jump *0x555555554997 |
1 |
|
1 | Continuing at 0x555555554997. |
- 失敗則會進到這個function
1
2
3
4
5void __noreturn alarm_handler()
{
puts("Not fast enough. BOOM!");
exit(0);
}
droids:0(賽後解出)
- android studio裝起來(先吃掉10G)
- logcat看個就有答案
droids:1(賽後解出)
- apktool配android studio
1 | ## direct methods |
- string的值會導向這邊C:\pinhan\ctf\apktool\one\res\values
droids:2(賽後解出)
reverse 出來的code
1
2
3
4
5
6
7
8
9
10
11
12
13public static String getFlag(String input, Context ctx) {
String[] witches = {"weatherwax", "ogg", "garlick", "nitt", "aching", "dismass"};
int second = 3 - 3;
int third = (3 / 3) + second;
int fourth = (third + third) - second;
int fifth = 3 + fourth;
int sixth = (fifth + second) - third;
String str = ".";
if (input.equals("".concat(witches[fifth]).concat(str).concat(witches[third]).concat(str).concat(witches[second]).concat(str).concat(witches[sixth]).concat(str).concat(witches[3]).concat(str).concat(witches[fourth]))) {
return sesame(input);
}
return "NOPE";
}整理之後的順序
1
dismass.ogg.weatherwax.aching.nitt.garlick
在拿去模擬器把字串拿進去跑,就有flag了
droids3(賽後解出)
reverse的code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class FlagstaffHill {
public static native String cilantro(String str);
public static String nope(String input) {
return "don't wanna";
}
public static String yep(String input) {
return cilantro(input);
}
public static String getFlag(String input, Context ctx) {
return nope(input);
}
}目標: 把nope換成yep,就能印出flag
- 參考以下code文章,改code再回包apk
把nope_function -> 改成yep_function
- 此題不用改太多,只須改function_name
- 流程
1
code改掉-> 重新輸出apk -> apk簽名的keystore -> 在apk上簽名 -> android_studio安裝
1 | apktool b .\three -o three_2.apk |
keytool
1
2
3
4
5-genkey 產生key
-alias 別名
-keystore 指定keystroe名字
-keyalg 密鑰算法
-validity 有效天數jarsigner
1
2-verbose 詳細齣齣
-keystore 證書儲存路徑
droids4(賽後解出)
1 | public static String getFlag(String input, Context ctx) { |
- 轉換一下好閱讀
1 | public static String getFlag(String input, Context ctx) { |
- 逆完結果
alphabetsoup
1 | printf("%c",(char)('a' + 0)); |
- 觀察function
1 | if (input.equals("".concat(queen.toString()).concat(jack.toString()).concat(ace.toString()).concat(king.toString()))) { |
- 如果成功= input,卻只能return call i,
- 因此要想辦法執行
public static native String cardamom(String str);
,步驟則跟前題一樣
- 因此要想辦法執行
- 改的部分
1
2
3
4
5
6
7
8
9
if-eqz v5, :cond_0
const-string v5, "call it"
invoke-static {p0}, Lcom/hellocmu/picoctf/FlagstaffHill;->cardamom(Ljava/lang/String;)Ljava/lang/String;
move-result-object v5
return-object v5