베지밀

[악성코드분석] Server-client 2, 1 본문

개인 공부/리버싱

[악성코드분석] Server-client 2, 1

vegimil 2024. 8. 9. 20:50

2가 더 쉬움

 

Server-client 2

 

IDA로 서버 코드를 열어보자

 

23번째 줄에서 연결이 수립되고, sub_401140 함수로 연결된다. (i는 아마도 소켓일 것이다)

해당 부분이 문제를 푸는 포인트인 것 같아서 진입해본다.

 

sub_401140 함수

아까 cmd창에서 본 문자열들이다.

사용자로부터 번호를 receive하고 input에 저장한다.

 

strncmp로 입력값을 비교해서 어떤 역할을 수행하는데, 7777이 보인다.

 

input 입력값에서 세미콜론을 찾고, 해당 위치 포인터를 v2에 반환한다.

그리고 ; 이후의 값부터 sub_401000함수로 넘겨준다.

 

sub_401000 함수

v2+1부터의 값은 Command라는 매개변수로 들어왔다.

buf라는 버퍼를 7777~ 문자열로 붙여놓고, 이후는 0으로 초기화한다.

🛞 _popen : 파이프를 만들고 명령어를 실행

_popen(Command, mode) → ‘r’은 명령의 표준출력을 읽어옴

사용자가 입력한 Command를 읽기모드로 가져와서 해당 결과를 변수에 저장하고 있다.

 

🛞 fgets : 스트링 읽기 (scanf와 비슷)

fgets(str, n stream) → stream에서 n만큼 읽어서 str에 저장 후 str 반환

명령어의 결과를 2048만큼 source에 저장하고 do while 문을 돈다.

 

buf의 크기가 2047보다 크면 멈추고, 그게 아니라면 strncpy함수를 반복한다.

 

🛞 strncpy : 문자열 복사

strncpy(dst, src, cnt) → src를 dst로 cnt만큼 복사 후 dst 반환

위 함수를 지나고 나면, buf는 다음과 같이 설정되어있을 것이다.

 

buf = “7777 IS MASTER KEY\n” + “command 결과”

 

sub_401000 함수는 return값으로 buf를 돌려주므로, 해당 함수가 실행되어야 원하는 command 결과를 볼 수 있을 것이다.

 

7777;뒤에 원하는 명령어를 입력하면 buf가 출력된다.

ls와 cat을 통해서 hidden_flag.txt를 출력했다.

FLAG{IDA_IS_GREATEST_OF_ALL_TIME}

 


Server-client 1

클라이언트는 포트 정보를 입력받게 되어있음

서버 코드에서 포트 정보를 알아내야 함!

 

서버 코드에는 socket, htons, bind, listen, accept 함수가 있음

서버는 통신을 위해 어떤 포트를 열건지 정의해줘야 함

name이라는 구조체에 네트워크 정보를 설정해주는 것임

 

sa_data[2]=0 → 자기 자신을 여는 것

sa_data → htons(host to network) 함수를 통해 포트 번호를 넣어주게 됨

    0x2013u = 8211번 포트

 

클라이언트 측에 포트번호를 입력하면 연결을 시도하고 Socket 검사를 한다.

연결이 정상적으로 성공됐다면 gethostbyname을 호출하게 됨

 

서버측에서는 accept를 함과 동시에 v4에 있는 값을 가지고 통신을 하게 됨

 

클라이언트측에서는 buf의 값을 send함

GetUserNameA와 GetComputerNameA의 문자열을 _로 합쳐서 buf에 넣음

디버거로 맞는지 확인해보자.

 

서버측을 보면 recevied_length가 12

(&Buf1 + i) = ((&buf + i) ^ 0x42) - 5;

 

Buf1과 408054의 값을 12바이트만큼 memcmp(비교)

버퍼는 유저가 보내준 값을 연산한다.

408054의 값을 확인해야 함

 

사용자가 보내준 값을 50번 줄의 연산을 통해서 408054의 값과 비교하고, 동일하면 flag를 줌

이 값을 역산해서 사용자가 보내야 하는 값을 구할 수 있음

408054 = ff09fe00180002110d0c1001

 

CyberChef로 역산하면 FLAG_GETPSWD가 나옴

Username이 FLAG이고, ComputerName이 GETPSWD여야 하는데, 그걸 바꿀 수는 없음...

 

따라서 디버거로 Client측 값을 변조해야 한다.

GetUserName과 GetComputerName을 받아오는 부분, 그 두 값을 연결하는 부분에 bp를 건다.

anon_ANON-PC라는 값이 잘 받아와졌다.

 

그렇다면 우리는 Send를 보내기 전에 해당 값을 FLAG_GETPSWD로 바꿔주어야 한다.

 

다시 프로그램을 실행시켜서 Get API 직후에 값을 원하는 대로 바꿔보자.

GetUserName과 GetComputerName에 bp를 걸고,

Ctrl+g와 Ctrl+e를 이용해서 메모리에서 값을 바꿔주었다.

 

sprinf까지 지나고 나면 스택에 변조시킨 값이 잘 들어간 것을 확인할 수 있다.

 

프로그램을 쭉 실행시켜서 MessageBoxA를 지나면 플래그가 뜨는 것을 확인할 수 있다!

flag{WELCOME_TO_REVERSE_ENGINEERING_WORLD}