WARGAME/pwnable.tw

pwnable.tw calc write-up

msh1307 2022. 8. 23. 00:55

statically linked 32bit 바이너리다.

PIE가 안 걸려있다.

간단한 계산기 프로그램이다.

timeout 걸어놓은 거 빼고 특별한 건 없다.

분석하면서 주석을 조금 달아놓았다.

get_expr 함수로 expression을 입력받고 parse_expr 함수로 최종적으로 결과가 프린트가 된다.

get_expr 함수이다.

 

화이트 리스트 기반으로 입력을 받는다.

공백 같은 문자들이 제거된다.

그리고 마지막에 NULL byte 하나 넣어준다.

 

init_pool은 v1을 0으로 초기화해준다.

 

parse_expr 함수의 일부다.

division by zero를 막으려고 operand가 0이면 다 리턴한다.

expression을 받아서 operator를 기준으로 operand를 int형 변수에 저장한다.

그리고 operand가 양수면 a2에 집어넣는다.

 

아까 1024짜리 input에서 v1으로 operand 옮기다 보면, bof가 터질 거라고 생각했다.

canary 때문에 힘들어 보여서 일단 보류하고 계속 코드를 읽었다.

여기서 파싱이 이루어지고 eval이 호출된다.

operator 다음에 operand 안 나오면 expression error! 를 출력하고 리턴한다.

계산 순서에 따라서 처리가 이루어지기도 한다.

 

eval 함수다.

 

operands[0]은 operand 총 개수 정도로 쓰이는 것 같다.

앞으로 a2도 operands로 부를 거다.

계산해서 앞에 꺼에다 집어넣는다.

 

parse_expr 과정에서 얘네들이 전체적으로 어떻게 동작하는지 확인해보기 위해서 gdb를 열었다.

calc + 116에 bp 걸어서 분석한 대로 동작하는지 확인한다.

10+12를 입력했다.

파라미터 두 개니까 두 개 다 확인해봤다.

아까 여기 s와 v1이다.

하나는 입력 그대로 들어갔고, 또 하나는 operand가 들어간다.

그리고 첫 번째 4바이트는 count 변수로 쓰인다.

count 변수는 현재 1이고, 10 + 12인 0x16이 그다음에 위치한다.

0xc는 12다.

아까 parse_expr 함수이다.

operand가 0이거나, operator 다음에 operand가 아닌 게 나오면 에러를 출력하고 리턴한다.

근데 처음에 operator에 대한 검사가 없다.

위처럼 입력하면 segmentation fault가 발생한다.

 

위 식은 operand count가 1이다.

여기서 operand[0]에 접근하게 된다.

bp를 걸고 +1234567을 입력했다.

eval 함수 안에서 add 부분이 끝나고 operand[]의 모습이다.

count 변수로 쓰이는 operand[0]이 덮였다.

1234567 + 1로 덮였다.

그리고 printf의 argument가 push 되는 과정에서 SIGSEGV가 뜬다.

operand[0]에 접근해서 그렇다.

 

여기서 operands[0]을 조작함으로써 OOB를 트리거할 수 있다.

인덱스를 잘 계산해서 스택도 leak 할 수 있다고 생각할 수 있다.

 

eval + 100에서 주소에 접근해서 add 한 값을 쓰니까 여기다 bp를 걸어야 한다.

입력으로는 +100+1234를 줬다.

add 연산이 되고 101이 count 변수에 들어간다.

다음 bp다. 

ecx에는 1234가 들어있다.

ecx는 operands와의 거리가 100인 주소에 쓰인다.

calc에 정의된 operands의 위치를 기준으로 인덱스를 알면, aaw를 트리거할 수 있다. 

 

statically linked 바이너리라서 가젯도 많고, sfp도 leak이 가능할 것 같아서, rop를 하면 된다.

$ebp랑 operands[] 사이의 거리는 0x5a 0이다.

leak을 하기 위해서 구했다.

4바이트짜리라서 4로 나눠야 된다.

 

eval 함수 내부에서 operands[0]과 operands[1]이 더해진다.

leak 할 때는 operands[0]이 1이니까 1이 더해진다.

그리고 eval 끝날 때 -1이 되니까 그냥 그대로 넣어주면 printf에서 leak이 된다.

 

aaw를 위해서 원래 있던 값을 더하거나 빼줘서 없애주고 주소를 넣어주면 된다.

sfp leak 하고, rop 해줬다.

execve로 쉘을 땄다. 

/bin/sh 주소를 넣는 건 음수가 나와서 따로 다른 로직을 짰다.

flag는 /home/calc 안에 있다.

'WARGAME > pwnable.tw' 카테고리의 다른 글

pwnable.tw orw write-up  (0) 2022.08.20
pwnable.tw start write-up  (0) 2022.08.20