블로그 이전했습니다. https://jeongzero.oopy.io/
[Christmas CTF 2020] lock
본문 바로가기
워게임/CTF 문제들

[Christmas CTF 2020] lock

728x90

1. 문제


요즘 건물들에는 굴뚝이 없어서 산타가 몰래 들어가서 선물을 줄 수가 없다… 그래서 열쇠를 몰래 딸 수 있는 당신을 고용했다. 그런데 이 도어락은 우리가 흔히 보던 것과 좀 다른 것 같은데…? 원리만 이해하면 쉽게 딸 수 있을 것 같다!

arm 어셈 덤프가 주어진다 - 다운로드

대회 당일 arm 어셈에 대한 지식이 부족해서 분석하다가 끝내 마무리하지 못했다. 롸업이 올라오고 나서 보니 그냥 분석해서 플래그 값을 얻어내면 되는 문제이다

2. 접근방법


main()

0000000000000c50 <main>:
 c50:	a9be7bfd 	stp	x29, x30, [sp, #-32]! //스택공간 확보, sp=sp-32, push x29, push x30
 c54:	910003fd 	mov	x29, sp //sp 를 x29에 복사
 c58:	d2800021 	mov	x1, #0x1                   	// #1 초기 x1=1
 c5c:	d2800260 	mov	x0, #0x13                  	// #19    x0=0x13
 c60:	97fffee0 	bl	7e0 <calloc@plt> //0x13만큼 동적할당하고 1로 초기화
 c64:	f9000be0 	str	x0, [sp, #16] //sp+16에 calloc한 주소 저장

 c68:	97ffff94 	bl	ab8 <sub_ab8>
 c6c:	97ffff51 	bl	9b0 <sub_9b0>

 c70:	f9000fe0 	str	x0, [sp, #24]
 c74:	97ffff3e 	bl	96c <sub_96c>
 c78:	f9400be1 	ldr	x1, [sp, #16]

 c7c:	90000000 	adrp	x0, 0 <_init-0x760>
 c80:	9138a000 	add	x0, x0, #0xe28              // #0xe28 '%s'
 c84:	97fffeeb 	bl	830 <__isoc99_scanf@plt>
 c88:	f9400fe1 	ldr	x1, [sp, #24]
 c8c:	f9400be0 	ldr	x0, [sp, #16]
 c90:	97ffffa8 	bl	b30 <sub_b30>
 c94:	f9400be0 	ldr	x0, [sp, #16]
 c98:	97fffee2 	bl	820 <free@plt>
 c9c:	52800000 	mov	w0, #0x0                   	// #0
 ca0:	a8c27bfd 	ldp	x29, x30, [sp], #32
 ca4:	d65f03c0 	ret
  • 몰랐던 instruction 위주로 설명하겠다. 우선 32바이트 만큼 스택을 확보하고, calloc(0x13,1)을 호출한다.
  • arm에서는 함수의 반환값을 x0 레지스터에 저장하므로 calloc을 통해 할당받은 힙주소를 sp+16에 저장한다. (buf)
  • sub_ab8() 함수를 호출한다. 반환되는 값은 x0에 담기므로 sub_9b0()은 x0를 인자로 하여 호출된다
  • 함수 호출의 인자는 x0, x1, x2 ... 순인므로 scanf("%s", buf) 사용자의 입력을 받은 뒤 buf에 저장한다
  • buf(sp+16)와, sub_9b0() 반환값(sp+24)를 인자로 하여 sub_b30()이 호출된다

메인함수를 수도코드로 포팅하면 다음과 같이 표현할 수 있다

int main()
{
	char* buf=calloc(0x13,1); //buf=sp+16

	a=sub_9b0(sub_ab8()); // a= sp+24

	b=sub_96c();

	scanf("%s",buf);

	sub_b30(buf,a);

	return 0;
}

sub_ab8()

0000000000000ab8 <sub_ab8>:
 ab8:	a9be7bfd 	stp	x29, x30, [sp, #-32]! // sp-32만큼 확보하고 sp=sp-32, push x29, x30
 abc:	910003fd 	mov	x29, sp // sp를 x29에 복사
 ac0:	52800103 	mov	w3, #0x8                   	// #8
 ac4:	90000000 	adrp	x0, value0@page // 명령 포인터 복사
 ac8:	9136e002 	add	x2, x0, value0@pageoff // x2=포인터+value0 즉, value2의 주소=>x2
 acc:	528007c1 	mov	w1, #0x3e                  	// #62
 ad0:	90000000 	adrp	x0, value1@page // x0=value1 주소
 ad4:	91372000 	add	x0, x0, value1@pageoff //x0=x0+value1주소

 ad8:	97ffffc9 	bl	9fc <sub_9fc>

 adc:	f9000fe0 	str	x0, [sp, #24]
 ae0:	f9400fe0 	ldr	x0, [sp, #24]
 ae4:	a8c27bfd 	ldp	x29, x30, [sp], #32
 ae8:	d65f03c0 	ret
  • sub_9fc()에 들어가는 인자 4개를 세팅한다(x0, w1, x2, w3)
    • (w- 계열 레지스터는 4byte 레지스터에고 8바이트 확장된게 x- 계열이다)
    • w3 = 0x8
    • x2 = value0
    • w1 = 0x3e
    • x0 = value1
  • sub_9fc(value1,0x3e,value0,w3)
  • 위 함수의 반환값을 ret한다

sub_ab8()함수를 포팅하면 다음과 같다

sub_ab8()
{
	return sub_9fc(value1,0x3e,value0,0x8); // a=sp+24
}

sub_9fc()

00000000000009fc <sub_9fc>:
 9fc:	a9bc7bfd 	stp	x29, x30, [sp, #-64]!
 a00:	910003fd 	mov	x29, sp
 a04:	f90017e0 	str	x0, [sp, #40] // x0=value1 주소
 a08:	b90027e1 	str	w1, [sp, #36] // w1=0x3e
 a0c:	f9000fe2 	str	x2, [sp, #24] // x2=value0 주소
 a10:	b90023e3 	str	w3, [sp, #32] // w3=8
 a14:	b94027e0 	ldr	w0, [sp, #36] // w0=0x3e
 a18:	11000400 	add	w0, w0, #0x1 // w0=0x3f
 a1c:	93407c00 	sxtw	x0, w0 
 a20:	97ffff68 	bl	7c0 <malloc@plt> // 0x3f 사이즈 동적할당

 a24:	f9001fe0 	str	x0, [sp, #56] // 할당받은 주소를 sp+56에 저장
 a28:	b98027e0 	ldrsw	x0, [sp, #36] // x0에 0x3e 저장
 a2c:	f9401fe1 	ldr	x1, [sp, #56] // 할당 받은 주소를 x1에 저장
 a30:	8b000020 	add	x0, x1, x0 // x0 = 할당받은 주소 + 0x3e

 a34:	3900001f 	strb	wzr, [x0] // wzr는 zero register. 항상 0이 들어감
 a38:	b90037ff 	str	wzr, [sp, #52]
 a3c:	14000018 	b	a9c <sub_9fc+0xa0> // ...a9c
---------------------------------------loop----------------------------------
 a40:	b98037e0 	ldrsw	x0, [sp, #52] // 초기값 0
 a44:	f94017e1 	ldr	x1, [sp, #40] //value1
 a48:	8b000020 	add	x0, x1, x0 // value1 주소 + x0
 a4c:	39400002 	ldrb	w2, [x0] // value1+x0에 담긴 한바이트를 w2에 저장
 a50:	b94037e0 	ldr	w0, [sp, #52] // 다시 초기값 0
 a54:	b94023e1 	ldr	w1, [sp, #32] // 8
 a58:	1ac10c03 	sdiv	w3, w0, w1 // index / 8
 a5c:	b94023e1 	ldr	w1, [sp, #32] 
 a60:	1b017c61 	mul	w1, w3, w1 // (index/8)*8
 a64:	4b010000 	sub	w0, w0, w1 // index - 8*(index/8)
 a68:	93407c00 	sxtw	x0, w0
 a6c:	f9400fe1 	ldr	x1, [sp, #24] //x1=value0
 a70:	8b000020 	add	x0, x1, x0 // x0 = value0 + x0
 a74:	39400001 	ldrb	w1, [x0] // value0 한바이트 가져오기
 a78:	b98037e0 	ldrsw	x0, [sp, #52]  // index
 a7c:	f9401fe3 	ldr	x3, [sp, #56] // buf
 a80:	8b000060 	add	x0, x3, x0 // buf + index
 a84:	4a010041 	eor	w1, w2, w1 // w1 =w2 ^ w1 
 a88:	12001c21 	and	w1, w1, #0xff // w1 = w1 & 0xff
 a8c:	39000001 	strb	w1, [x0]
 a90:	b94037e0 	ldr	w0, [sp, #52]
 a94:	11000400 	add	w0, w0, #0x1 // index++
 a98:	b90037e0 	str	w0, [sp, #52]

 a9c:	b94037e1 	ldr	w1, [sp, #52] // 초기값 0
 aa0:	b94027e0 	ldr	w0, [sp, #36] // 0x3e
 aa4:	6b00003f 	cmp	w1, w0
 aa8:	54fffccb 	b.lt	a40 <sub_9fc+0x44>  // b.tstop
------------------------------------------------------------------------------
 aac:	f9401fe0 	ldr	x0, [sp, #56]
 ab0:	a8c47bfd 	ldp	x29, x30, [sp], #64
 ab4:	d65f03c0 	ret
  • 넘어온 인자 4개를 변수에 저장한다
  • 0x3e+1 만큼 malloc한다
  • str wzr, [sp, #52] ⇒ wzr은 항상 0이 저장되고 0이 읽히는 레지스터이다. 따라서 sp+52에 0을 집어넣는다
  • sub_9fc+0xa0 로 이동한다 ⇒ 0x..a9c
  • sp+52 값인 0을 w1에 넣고, sp+36인 0x3e를 w0에 넣은뒤 두 개를 서로 배교한다. w1이 더 작으면 sub_9fc+0x44 ⇒ 0x..a40으로 다시 이동한다
  • sp+52를 인덱스로하여 특정 연산지 진행된다
     a50:	b94037e0 	ldr	w0, [sp, #52] // 다시 초기값 0
     a54:	b94023e1 	ldr	w1, [sp, #32] // 8
     a58:	1ac10c03 	sdiv	w3, w0, w1 // index / 8
     a5c:	b94023e1 	ldr	w1, [sp, #32] 
     a60:	1b017c61 	mul	w1, w3, w1 // (index/8)*8
     a64:	4b010000 	sub	w0, w0, w1 // index = index - 8*(index/8)
     a68:	93407c00 	sxtw	x0, w0
    1. value1 + index 의 한바이트 값을 가져온다. 초기 index(w0)는 0이다
    1. sp+32는 8이므로 w1에 저장한다
    1. (sp+52) - ((sp+52)/8) * 8 연산을 진행한다
    1. 이 연산의 의미는 index = index - 8*(index/8) 이고 해당 index가 다음 루프의 index로 사용된다. 즉 value1[index %8] 로 해석하면 된다
    1. 계산된 w0를 singed 부호확장을 진행하여 x0에 저장한다.
  • sp+52를 인덱스로 하여 이번에는 value0의 한바이트를 가져온다.
    • value[index]
  • 위에서 구한 두개의 값을 xor 연산하고 0xff와 and 연산을 진행한다
    • ( value1[index%8] ^ value0[index] ) & 0xff
  • 계산된 한바이트를 malloc buf에 저장한다
  • 루프가 끝나면 buf의 주소를 반환한다

해당 함수는 다음과 같이 표현 가능하다

sub_9fc(char* value1, int len, char* value0, int b)
{
	char* arg1=value1;
	int arg2=a; //0x3e
	char* arg3=value0;
	int arg4=b; //8

	char* buf=malloc(arg2+1); // buf = sp+56
	buf+0x3e=0;

	for(i=0;i<len;i++)
	{
		buf[i]=( value0[i] ^ value1[i%b] ) & 0xff; 
	}

	return buf;
}

sub_9b0()

00000000000009b0 <sub_9b0>:
 9b0:	a9bd7bfd 	stp	x29, x30, [sp, #-48]!
 9b4:	910003fd 	mov	x29, sp
 9b8:	f9000fe0 	str	x0, [sp, #24] // sub_9fc의 반환 값 저장
 9bc:	f9400fe0 	ldr	x0, [sp, #24]
 9c0:	97ffff78 	bl	7a0 <strlen@plt>
 9c4:	91000400 	add	x0, x0, #0x1
 9c8:	97ffff7e 	bl	7c0 <malloc@plt>
 9cc:	f90017e0 	str	x0, [sp, #40]
 9d0:	f94017e0 	ldr	x0, [sp, #40]
 9d4:	f100001f 	cmp	x0, #0x0
 9d8:	54000061 	b.ne	9e4 <sub_9b0+0x34>  // b.any
 9dc:	d2800000 	mov	x0, #0x0                // #0
 9e0:	14000005 	b	9f4 <sub_9b0+0x44>

 9e4:	f9400fe1 	ldr	x1, [sp, #24]
 9e8:	f94017e0 	ldr	x0, [sp, #40]
 9ec:	97ffff95 	bl	840 <strcpy@plt>
 9f0:	f94017e0 	ldr	x0, [sp, #40]
 9f4:	a8c37bfd 	ldp	x29, x30, [sp], #48
 9f8:	d65f03c0 	ret
  • 인자로 넘어온 연산된 값이 저장된 buf를 인자로 strlen이 호출된다. buf의 사이즈를 계산한다
  • strlen을 통해 얻은 사이즈 + 1만큼 malloc을 한다
  • 할당받은 주소가 0이면 0x..9f4로 분기해서 종료되고 아니면 0x..9e4로 분기한다
  • sp+24인 buf의 주소와 할당받은 주소인 sp+40을 인자로 strcpy를 호출한다
  • 즉 새롭게 할당받은 영역에 연산된 buf 를 복사하고 buf를 반환한다

위 함수는 다음과 같이 표현 할 수 있다

sub_9b0(int data)
{
	b=strlen(data);
	char* buf=malloc(b+1); //buf = sp+40
	if(buf)
	{ 
		strcpy(buf,data);
		return buf;
	}
	else
	{
		return 0;
	}
}

sub_b30(buf,a)

0000000000000b30 <sub_b30>:
 b30:	a9be7bfd 	stp	x29, x30, [sp, #-32]!
 b34:	910003fd 	mov	x29, sp
 b38:	f9000fe0 	str	x0, [sp, #24] // x0값을 sp+24에 저장
 b3c:	f9000be1 	str	x1, [sp, #16] // x1값을 sp+16에 저장
 b40:	f9400fe0 	ldr	x0, [sp, #24] // sp+24를 읽어서 x0에 저장
 b44:	91001800 	add	x0, x0, #0x6 // x0 = x0 + 6
 b48:	39400001 	ldrb	w1, [x0] //x0에 들어있는 한바이트를 w1에 저장
 b4c:	f9400be0 	ldr	x0, [sp, #16] // sp+16을 읽어서 xo에 저장
 b50:	91003800 	add	x0, x0, #0xe // x0 = x0+ 0xe
 b54:	39400000 	ldrb	w0, [x0] // x0에 들어있는 한바이트를 w0에 저장
 b58:	6b00003f 	cmp	w1, w0
 b5c:	54000761 	b.ne	c48 <sub_b30+0x118>  // b.any
 b60:	f9400fe0 	ldr	x0, [sp, #24]
 b64:	91001000 	add	x0, x0, #0x4
 b68:	39400001 	ldrb	w1, [x0]
 b6c:	f9400be0 	ldr	x0, [sp, #16]
 b70:	91000c00 	add	x0, x0, #0x3
 b74:	39400000 	ldrb	w0, [x0]
 b78:	6b00003f 	cmp	w1, w0
 b7c:	54000661 	b.ne	c48 <sub_b30+0x118>  // b.any
 b80:	f9400fe0 	ldr	x0, [sp, #24]
 b84:	91000c00 	add	x0, x0, #0x3
 b88:	39400001 	ldrb	w1, [x0]
 b8c:	f9400be0 	ldr	x0, [sp, #16]
 b90:	91002800 	add	x0, x0, #0xa
 b94:	39400000 	ldrb	w0, [x0]
 b98:	6b00003f 	cmp	w1, w0
 b9c:	54000561 	b.ne	c48 <sub_b30+0x118>  // b.any
 ba0:	f9400fe0 	ldr	x0, [sp, #24]
 ba4:	91001c00 	add	x0, x0, #0x7
 ba8:	39400001 	ldrb	w1, [x0]
 bac:	f9400be0 	ldr	x0, [sp, #16]
 bb0:	91004400 	add	x0, x0, #0x11
 bb4:	39400000 	ldrb	w0, [x0]
 bb8:	6b00003f 	cmp	w1, w0
 bbc:	54000461 	b.ne	c48 <sub_b30+0x118>  // b.any
 bc0:	f9400fe0 	ldr	x0, [sp, #24]
 bc4:	91000400 	add	x0, x0, #0x1
 bc8:	39400001 	ldrb	w1, [x0]
 bcc:	f9400be0 	ldr	x0, [sp, #16]
 bd0:	91003800 	add	x0, x0, #0xe
 bd4:	39400000 	ldrb	w0, [x0]
 bd8:	6b00003f 	cmp	w1, w0
 bdc:	54000361 	b.ne	c48 <sub_b30+0x118>  // b.any
 be0:	f9400fe0 	ldr	x0, [sp, #24]
 be4:	91001400 	add	x0, x0, #0x5
 be8:	39400001 	ldrb	w1, [x0]
 bec:	f9400be0 	ldr	x0, [sp, #16]
 bf0:	9100d000 	add	x0, x0, #0x34
 bf4:	39400000 	ldrb	w0, [x0]
 bf8:	6b00003f 	cmp	w1, w0
 bfc:	54000261 	b.ne	c48 <sub_b30+0x118>  // b.any
 c00:	f9400fe0 	ldr	x0, [sp, #24]
 c04:	39400001 	ldrb	w1, [x0]
 c08:	f9400be0 	ldr	x0, [sp, #16]
 c0c:	9100d400 	add	x0, x0, #0x35
 c10:	39400000 	ldrb	w0, [x0]
 c14:	6b00003f 	cmp	w1, w0
 c18:	54000181 	b.ne	c48 <sub_b30+0x118>  // b.any
 c1c:	f9400fe0 	ldr	x0, [sp, #24]
 c20:	91000800 	add	x0, x0, #0x2
 c24:	39400001 	ldrb	w1, [x0]
 c28:	f9400be0 	ldr	x0, [sp, #16]
 c2c:	91000800 	add	x0, x0, #0x2
 c30:	39400000 	ldrb	w0, [x0]
 c34:	6b00003f 	cmp	w1, w0
 c38:	54000081 	b.ne	c48 <sub_b30+0x118>  // b.any
 c3c:	f9400fe0 	ldr	x0, [sp, #24]
c40:	97ffffab 	bl	aec <sub_aec>
 c44:	d503201f 	nop
 c48:	a8c27bfd 	ldp	x29, x30, [sp], #32
 c4c:	d65f03c0 	ret
  • 사용자가 입력한 값과 특정 연산이 수행된 값을 비교한다.
  • 사용자의 입력값 8바이트를 각각 비교한다. 이를 다음과 같이 표현 할 수 있다
      a=a+6;
    	b=b+0xe;
    	w1=*a;
    	x0=*b;
    
    	a=a+4;
    	b=b+3;
    	w1=*a;
    	x0=*b;
    
    	a=a+3;
    	b=b+0xa;
    	w1=*a;
    	x0=*b;
    
    	a=a+7;
    	b=b+0x11;
    	w1=*a;
    	x0=*b;
    
    	a=a+1;
    	b=b+0xe;
    	w1=*a;
    	x0=*b;
    
    	a=a+5;
    	b=b+0x34;
    	w1=*a;
    	x0=*b;
    
    	a=a+0;
    	b=b+0x35;
    	w1=*a;
    	x0=*b;
    
    	a=a+2;
    	b=b+0x2;
    	w1=*a;
    	x0=*b;
  • 8개의 조건을 다 만족한다면 이를 인자로 하여 sub_aec 함수를 호출한다

sub_aec(a)

0000000000000aec <sub_aec>:
 aec:	a9bd7bfd 	stp	x29, x30, [sp, #-48]!
 af0:	910003fd 	mov	x29, sp
 af4:	f9000fe0 	str	x0, [sp, #24] // buf
 af8:	f9400fe0 	ldr	x0, [sp, #24]
 afc:	97ffff29 	bl	7a0 <strlen@plt>
 b00:	2a0003e3 	mov	w3, w0
 b04:	f9400fe2 	ldr	x2, [sp, #24]
 b08:	528003e1 	mov	w1, #0x1f                  	// #31
 b0c:	90000000 	adrp	x0, value2@page
 b10:	91382000 	add	x0, x0, value2@pageoff
 b14:	97ffffba 	bl	9fc <sub_9fc>
 b18:	f90017e0 	str	x0, [sp, #40]
 b1c:	f94017e0 	ldr	x0, [sp, #40]
 b20:	97ffff3c 	bl	810 <puts@plt>
 b24:	d503201f 	nop
 b28:	a8c37bfd 	ldp	x29, x30, [sp], #48
 b2c:	d65f03c0 	ret
  • 사용자 입력값의 사이즈를 strlen을 통하여 얻는다
  • 아까 봤던 sub_9fc()를 호출한다. 들어가는 인자는 다음과 같다
    1. x0 : value2 주소
    1. w1 : 0x1f
    1. w2 : 사용자 입력값 주소
    1. w3 : strlen을 통해서 얻은 사용자 입력 값 사이즈

3. 풀이


코드 분석은 다했다. 중요한 부분은 결국 다음과 같다

  1. value0, value1을 통해서 계산되는 buf의 값을 구한다
    value1 = [
        0xF7, 0x7B, 0x64, 0x75, 0xFC, 0x7F, 0x65, 0x79, 0xFF,
        0x73, 0x6C, 0x7D, 0xF4, 0x77, 0x6D, 0x61, 0xE7, 0x6B, 0x74, 0x65,
        0xEC, 0x6F, 0x75, 0x69, 0xEF, 0x63, 0x46, 0x53, 0xDA, 0x5D, 0x47,
        0x57, 0xD1, 0x51, 0x4E, 0x5B, 0xD2, 0x55, 0x4F, 0x5F, 0xD9, 0x49, 0x56,
        0x43, 0xCA, 0x4D, 0x57, 0x47, 0xC1, 0x41, 0x5E, 0x4B, 0xA9, 0x28, 0x30,
        0x22, 0xA2, 0x2C, 0x31, 0x26, 0xA1, 0x20
    ]
    
    value0 = [0x96, 0x19, 0x7, 0x11, 0x99, 0x19, 0x2, 0x11]
    
    value2 = [
        0x69, 0x22, 0x22, 0x38, 0x1F, 0x43, 0x5B, 0x1C, 0x45, 0xE, 0x3C,
    0x8, 0x5, 0x5E, 0x30, 0x17, 0x5F, 0x1B, 0x6, 0x19, 0x3B, 0x44, 0x7, 0x17,
    0x6E, 0x7, 0x53, 0x1E, 0x17, 0x55, 0x12
    ]
    
    buf = ""
    
    for i in range(0x3E):
        buf += chr((value1[i] ^ value0[i % 8]) & 0xFF)
    
    print(buf)
    
    ================================================================================
    
    E:\JungJaeho\STUDY\Self\hacking\ctf\chrismasctf\c545e718-b031-4028-876c-1998a6ab071e> 
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 // 연산된 값
  1. 사용자 입력값 8바이트와 1번을 통해 얻은 buf의 특정 인덱스 별 바이트 값을 비교하여 동일하게 세팅한다
    ...
    my_input = ""
    my_input += buf[0x35]
    my_input += buf[0xE]
    my_input += buf[0x2]
    my_input += buf[0xA]
    my_input += buf[0x3]
    my_input += buf[0x34]
    my_input += buf[0xE]
    my_input += buf[0x11]
    
    print(my_input)
    ================================================================================
    
    E:\JungJaeho\STUDY\Self\hacking\ctf\chrismasctf\c545e718-b031-4028-876c-1998a6ab071e> 
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 // 연산된 값
    1ockd0or // 사용자가 입력해야하는 값!!
    

  1. 2번을 통해 얻은 사용자 입력값을 인자로 다시 특정 연산을 거친뒤 출력한다
    ...
    result = ""
    
    for i in range(0x1F):
        result += chr((value2[i] ^ ord(my_input[i % len(my_input)])) & 0xFF)
    
    print(result)
    ================================================================================
    
    E:\JungJaeho\STUDY\Self\hacking\ctf\chrismasctf\c545e718-b031-4028-876c-1998a6ab071e> 
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 // 연산된 값
    1ockd0or // 사용자가 입력해야하는 값!!
    XMAS{s4nta_can_enter_the_h0use}

최종 페이로드는 다음과 같다

value1 = [
    0xF7, 0x7B, 0x64, 0x75, 0xFC, 0x7F, 0x65, 0x79, 0xFF,
    0x73, 0x6C, 0x7D, 0xF4, 0x77, 0x6D, 0x61, 0xE7, 0x6B, 0x74, 0x65,
    0xEC, 0x6F, 0x75, 0x69, 0xEF, 0x63, 0x46, 0x53, 0xDA, 0x5D, 0x47,
    0x57, 0xD1, 0x51, 0x4E, 0x5B, 0xD2, 0x55, 0x4F, 0x5F, 0xD9, 0x49, 0x56,
    0x43, 0xCA, 0x4D, 0x57, 0x47, 0xC1, 0x41, 0x5E, 0x4B, 0xA9, 0x28, 0x30,
    0x22, 0xA2, 0x2C, 0x31, 0x26, 0xA1, 0x20
]

value0 = [0x96, 0x19, 0x7, 0x11, 0x99, 0x19, 0x2, 0x11]

value2 = [
    0x69, 0x22, 0x22, 0x38, 0x1F, 0x43, 0x5B, 0x1C, 0x45, 0xE, 0x3C,
0x8, 0x5, 0x5E, 0x30, 0x17, 0x5F, 0x1B, 0x6, 0x19, 0x3B, 0x44, 0x7, 0x17,
0x6E, 0x7, 0x53, 0x1E, 0x17, 0x55, 0x12
]

buf = ""

for i in range(0x3E):
    buf += chr((value1[i] ^ value0[i % 8]) & 0xFF)

print(buf)

my_input = ""
my_input += buf[0x35]
my_input += buf[0xE]
my_input += buf[0x2]
my_input += buf[0xA]
my_input += buf[0x3]
my_input += buf[0x34]
my_input += buf[0xE]
my_input += buf[0x11]

print(my_input)

result = ""

for i in range(0x1F):
    result += chr((value2[i] ^ ord(my_input[i % len(my_input)])) & 0xFF)

print(result)

4. 몰랐던 개념


  • arm 어셈 (aarch64)
  • str, ldr 순서. str은 ⇒, ldr은 <=
  • sxtw : signed 부호 확장 명령어
  • wzr : zero register로서 항상 0이 들어간다

5. 참고자료


728x90

'워게임 > CTF 문제들' 카테고리의 다른 글

[Christmas CTF 2020] angrforge  (0) 2021.01.16
[Christmas CTF 2020] phantom  (0) 2021.01.15
[Christmas CTF 2020] show me the pcap  (0) 2021.01.14
[star CTF 2019] hack me  (0) 2020.12.17
[0ctf 2019] babykernel2  (0) 2020.12.08