reversing 28

2023 cce 청소년부 3등(2023 cyber conflict exercise junior 3rd)

2023 사이버 공격 방어 대회에서 극적으로 3등을 해냈다. 이번 대회는 웹 문제 빼고 풀만한 게 없어서 리버싱만 했던 나는 포너블 하던 친구랑 바이너리 패치 문제를 같이 풀었다. 바이너리 패치 문제의 코드는 생각보다 간단해서 분석하는데 오래 걸리지 않았고 그 분석을 토대로 친구가 취약점을 찾아 패치하는 식으로 진행했다. 총 바이너리 패치 2개, 웹 2문제를 풀어 3등을 따냈고, 내년에는 지금 3학년들이 일반부로 떠나게 되니 2등이나 잘되면 1등을 따낼 수 있을 것 같다.

reversing 2023.07.13

[reversing] Go 바이너리 분석

ctftime.org에서 Go 바이너리를 발견해 Go 공부를 시작했다. C언어로 개발하던 짬이 있어선지 언어 습득은 2시간 정도 걸렸고, 그렇게 습득한 언어로 여러가지 코드를 짜보며 어셈으론 어떻게 나오는지 확인해봤다. 1. 함수 호출 함수를 호출할 때 인자를 어떻게 전달하는지 알아보기 위해 인자를 10개로 갖는 함수를 하나 선언하고, 어셈블리어로 확인해봤다. C언어에서는 rdi, rsi, rdx, rcx ... 순으로 인자가 전달됐는데, Go에서는 인자가 rax, rbx, rcx, rdi, rsi, r8, r9, r10, r11 .... 이런 식으로 전달된다. 가변 인자는 C언어와 비슷하게 스택에 쌓고 가변 인자의 시작 주소와 개수를 전달한다. 가변 인자와 관련해 발견한 특징 중 하나는 인자 하나당 1..

reversing 2023.02.23

[layer7 ctf] 리버싱 라이트업(총 2문제)

1. tea_time 일단 문제 파일을 열자마자 프로그램 루틴이 보였다. int __cdecl main(int argc, const char **argv, const char **envp) { char v4; // al int i; // [rsp+8h] [rbp-188h] int v7; // [rsp+Ch] [rbp-184h] unsigned int v8; // [rsp+10h] [rbp-180h] unsigned int v9; // [rsp+14h] [rbp-17Ch] int v10; // [rsp+1Ch] [rbp-174h] int j; // [rsp+20h] [rbp-170h] int k; // [rsp+24h] [rbp-16Ch] char *v13; // [rsp+28h] [rbp-168h] in..

reversing 2022.12.19

Layer7 리버싱 11차시 과제(VM) - prob4

문제 파일을 IDA로 열어 main함수부터 분석해보았다. prob3와 같았다. 사용자로부터 32개의 문자를 입력받고, 그 입력값에 어떤 연산을 수행한 후, 후에 특정 조건과 비교해 만족한다면 Correct!, 다르면 Wrong...을 출력하고 있다. init_cpu는 이전 문제처럼 v5에 입력값을 복사하는 역할이었고, run_cpu는 이전 문제와 모두 같고, 데이터만 달랐다. 그래서 조건 분기 부분을 처리하기 위해 prob3처럼 식을 추출하지 말고 그 자리에서 계산해줬고, 마지막에 플래그를 순서대로 출력해 출력조건을 맞춰주었다. 그럼 구현해보자. 일단, 프로그램의 로직대로 연산을 수행하기 위해 stub코드를 추출해줬고, run_cpu의 코드도 파이썬으로 새롭게 짜줬다. 그 후, 플래그의 순서대로 출력하면..

reversing 2022.08.30

layer7 리버싱 11차시 과제(VM) - prob3

일단 문제 파일을 내려받아 아이다로 열어보았다. 대충 사용자로부터 32개의 문자를 입력받고, 그 문자에 대한 연산을 수행한 후, 그 연산 결과가 아래 조건문과 일치하는지 보고 일치하면 Correct!, 다르면 Wrong...을 출력하는 코드이다. 그럼 사용자로부터 입력받은 후의 첫번째 함수인 init_cpu를 보자. 사용자로부터 입력받은 값을 v5라는 새로운 배열에 복사하는 코드였다. 그럼 다음 코드, run_cpu 부분을 확인해보자. 다른 VM 문제와 같은 형식이었다. stub이라는 배열에 들어있는 값에 따라 연산을 수행해나가는 코드였다. 처음엔 그냥 "코드 그대로 가져다 써서 식 추출한 다음에 그대로 z3-solver 돌리면 되겠지"라고 생각했으나, 밑에 있는 조건문을 보고 생각이 달라졌다. 이렇게 ..

reversing 2022.08.30

Layer7 리버싱 10차시 과제(VM) - prob1

일단 파일을 아이다로 열어 분석해보았다. 대충 사용자로부터 48바이트 문자열을 입력받은 후, v5배열에 내용을 복사하고, run_cpu 함수를 수행한 후에 v5의 15번째 문자가 0(NULL)문자가 아니면 Wrong..., 0이 아니면 Correct!를 출력하고 있다. 우리의 역할은 v5의 15번째 문자가 0이 되는 문자열을 찾아야하는 것이다. 따라서 run_cpu의 내용을 분석해보았다. 바로 전 문제와 크게 다른 게 없었다. 그냥 stub 배열의 값에 따라서 문자열을 변조하는 코드였는데, 이 모든 코드를 복사하고, 값을 변조하는 부분만 문자열로 출력해준다면, 제대로 된 값이 나올 것이다. 일단 코드를 짜기 전 stub의 내용을 [shift+E]로 복사해주었다. 그 후, 이런 식으로 C++ 코드로 복사해..

reversing 2022.08.24

Layer7 리버싱 10차시 과제(VM) - prob for beginner

일단 문제를 내려받고 아이다를 통해 열어보았다. 이런 식의 코드가 나왔다. 사용자로부터 16자리 플래그를 입력받고, initcpu, runcpu 두 개의 함수를 거친 후에 v5의 HIDWORD값이 참이라면 Wrong.., 거짓이라면 Correct!를 출력하고 있다. 내용을 보니 v5의 HIDWORD값이 거짓이 나오게 해야할 것 같은데, HIDWORD가 무엇일까? 인터넷에 쳐보니, 상위 4바이트라고 한다. (Hi(GH) DWORD) 흠, 아무래도 v4변수는 v5까지 포함하는 것 같은데, 아이다가 해석을 잘못한 것 같다. y키를 이용해 v4의 크기를 4로 바꿔주자. 이런 식으로 문자열 형식으로 바꿔주면, 아까는 HIDWORD로 표현되던 부분이 이런 식으로 바뀐다. 따라서 v4의 4번째 인덱스에 들어있는 값의..

reversing 2022.08.24

Layer7 리버싱 9차시 과제 - prob4 풀이

이번에도 prob3와 마찬가지로 소스에서 Correct!를 출력하는 부분을 실행시키는 것이 목표인 것 같다. 따라서 저 조건에 맞는 입력을 넣어야 되는데, 미지수가 총 4개이고, 식은 8개이다. 따라서 미지수보다 식의 개수가 많으므로 충분히 풀 수 있다. z3-solver를 이용해 한 번 풀어보자. 일단, unsigned long long형으로 자료를 선언해야하는데, 중간에 xor 등 비트연산자가 나오므로 비트벡터 형식으로 선언해야 한다. 이런 식으로 미지수 4개를 unsigned long long(64비트)의 비트벡터 형식으로 선언했다. 그 후, 임의의 변수에 Solver 객체를 할당하고, 식을 모두 추가한 뒤 check()를 호출하면 방정식이 풀렸다는 뜻의 sat이 출력될 것이다. 이런 식으로 if문..

reversing 2022.08.17

Layer7 리버싱 9차시 과제 - prob3 풀이

이번 과제는 친절하게도 익숙한 C++파일이었고, 내용은 C언어와 다를 게 없었다. 따라서 문자열을 문자 변수 여러개로 인식해서 보기 불편하게 만드는 불상사는 생기지 않았다. 한 번 코드를 살펴보자. 이런 식으로 16자리 문자열을 입력받은 후, 문자열에 대해 특정 연산을 수행한 후에 그 연산 결과가 조건을 만족시키면 Correct!, 다르면 Wrong...을 출력하고 있다. 아마 Correct!를 출력해야 플래그가 나올 것 같기에 저 식을 z3-solver로 풀어 해를 구하면 될 것 같다. (참고로 미지수의 개수만큼 식이 있어야 식을 풀 수 있는데 위의 조건문엔 식이 총 16개이므로, 사용자 입력의 길이와 같아 해를 구할 수 있는 조건을 만족한다. 그럼 한 번 구현해보자. 일단, 비트연산자들은 보이지 않으..

reversing 2022.08.16

Layer7 리버싱 9차시 과제 - prob1 풀이

일단 ida64로 실행파일을 열어보았다. main함수의 초반 부분은 이런데, prob-begin 문제와 같이 %s 형식 지정자로 입력받지만, v4변수가 long long형이기 때문에 char[16]형으로 바꿔주었다. 바꾸기를 원하는 변수를 클릭하고 y키를 누르면 변수 타입을 바꿀 수 있다. 이렇게 변수를 바꿔준 후, 밑에 있는 if문으로 확인했다. 이런 식으로 아주 긴 조건문이 나왔는데, 잘 보면 v4의 0번째부터 QWORD만큼(즉, 8바이트)을 가져와서 쓰고 있다. 이 말은 입력받은 16자리 문자열을 8바이트짜리 long long형 두 개로 바꿔 사용하고 있다는 것이다. 따라서 우린 z3-solver로 방정식을 풀기 전, 변수를 선언할 때 long long의 크기만큼으로 선언해야 하고, 중간에 xor같..

reversing 2022.08.16