#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/socket.h>
int s_serverSocket;
void hacker_shell() {
printf("The system has been taken over by hackers /bin/sh...\n");
}
void safe_handler() {
printf("Safely end.\n");
}
struct NAS_Memory_Block {
char* buffer;
void (*error_handler)();
};
void InitServerSocket(int port)
{
int ret;
int sockFd;
int optEnable;
struct sockaddr_in serverAddr = { 0 };
sockFd = socket(AF_INET, SOCK_STREAM, 0);
if (sockFd < 0)
printf("Could not create server socket: %s\n", strerror(errno));
optEnable = 1;
setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &optEnable, sizeof(optEnable));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); //remote connect
//serverAddr.sin_addr.s_addr= inet_addr("127.0.0.1"); //local connect
serverAddr.sin_port = htons(port);
ret = bind(sockFd, (struct sockaddr*) &serverAddr, sizeof(serverAddr));
if (ret < 0)
printf("Could not bind serverAddr socket: %s\n", strerror(errno));
ret = listen(sockFd, SOMAXCONN);
if (ret < 0)
printf("Could not listen: %s\n", strerror(errno));
s_serverSocket = sockFd;
}
//After attacker run into AcceptData heap_block->error_handler can go to hacker_shell
void AcceptData() {
uint16_t packet_len;
uint16_t alloc_size;
int maxFd;
int acceptFd;
int len;
fd_set fdSvSet;
fd_set fdRdSet;
struct sockaddr_in clientAddr;
struct timeval timeoutMonitor;
socklen_t addrLen;
FD_ZERO(&fdSvSet);
FD_SET(s_serverSocket, &fdSvSet);
fdRdSet = fdSvSet;
//need do every time, after select will auto reset
timeoutMonitor.tv_sec = 60;
timeoutMonitor.tv_usec = 0;
maxFd = s_serverSocket;
//use select monitor all sockets of list
if (select(maxFd+1, &fdRdSet, NULL, NULL, &timeoutMonitor) == -1)
{
printf("Server select failure \n");
}
addrLen = sizeof(clientAddr);
memset(&clientAddr, 0, sizeof(clientAddr));
acceptFd = accept(s_serverSocket, (struct sockaddr*)&clientAddr, &addrLen);
if (acceptFd < 0)
return;
printf("DEBUG: hacker_shell = %p\n", &hacker_shell);
printf("DEBUG: safe_handler = %p\n", &safe_handler);
struct NAS_Memory_Block* heap_block = (struct NAS_Memory_Block*)malloc(sizeof(struct NAS_Memory_Block));
recv(acceptFd, &packet_len, 2, 0);
alloc_size = packet_len + 2;
if( alloc_size < 8192 )
{
printf("Integer overflow is triggered when alloc_size becomes 1\n");
alloc_size = packet_len + 2;
heap_block->buffer = (char*)malloc(alloc_size);
}
heap_block->error_handler = safe_handler;
printf("DEBUG: heap_block->error_handler = %p\n", heap_block->error_handler);
recv(acceptFd, heap_block->buffer, packet_len, 0);
printf("DEBUG: heap_block->error_handler = %p\n", heap_block->error_handler);
heap_block->error_handler();
}
/* Due to cybersecurity concerns, the attack code is not publicly available */
int ClientSend(char* szip, int port)
{
...
return true;
}
int main(int argc, char** argv)
{
uint16_t a = 5;
uint16_t b = 10;
// Implicit conversion show you
if ((a - b) > 0) {
printf("The answer is greater than 0!!\n");
} else {
printf("Answer is less than or equal to 0 !!\n");
}
#if 1
InitServerSocket(9006);
AcceptData();
#else
ClientSend("192.168.1.100", 9006);
#endif
return 0;
}
********* Defense for hacker attack *********
#define MAX_ALLOWED_PACKET 8190 // 8192 - 2, keeping the total size strictly within safe bounds
void AcceptData() {
//int64_t overflow is undefined behavior
uint64_t packet_len = 0;
uint64_t alloc_size = 0;
int maxFd;
int acceptFd;
fd_set fdSvSet;
fd_set fdRdSet;
struct sockaddr_in clientAddr;
struct timeval timeoutMonitor;
socklen_t addrLen;
// Initialize socket sets for select() multiplexing
FD_ZERO(&fdSvSet);
FD_SET(s_serverSocket, &fdSvSet);
fdRdSet = fdSvSet;
// Set explicit monitoring timeout to prevent connection hanging (DoS mitigation)
timeoutMonitor.tv_sec = 60;
timeoutMonitor.tv_usec = 0;
maxFd = s_serverSocket;
if (select(maxFd+1, &fdRdSet, NULL, NULL, &timeoutMonitor) == -1)
{
printf("Server select failure \n");
}
addrLen = sizeof(clientAddr);
memset(&clientAddr, 0, sizeof(clientAddr));
// Accept incoming client connection
acceptFd = accept(s_serverSocket, (struct sockaddr*)&clientAddr, &addrLen);
if (acceptFd < 0) {
return;
}
printf("DEBUG: hacker_shell = %p\n", &hacker_shell);
printf("DEBUG: safe_handler = %p\n", &safe_handler);
// SECURE STEP 1: Allocate the core structure block and immediately validate against NULL
struct NAS_Memory_Block* heap_block = (struct NAS_Memory_Block*)malloc(sizeof(struct NAS_Memory_Block));
if (heap_block == NULL) {
close(acceptFd);
return;
}
// DEFENSIVE: Initialize pointer to NULL to prevent dangling pointer bugs
heap_block->buffer = NULL;
// SECURE STEP 2: Read exactly 2 bytes for the length header and strictly verify the return value
// This prevents partial read exploits or blocked streams from introducing garbage data
if (recv(acceptFd, &packet_len, 2, 0) != 2) {
printf("DEBUG: Failed to read full packet length header\n");
free(heap_block);
close(acceptFd);
return;
}
// SECURE STEP 3: Input Validation and Business Boundary Definition
// Define a strict maximum threshold to prevent resource exhaustion and integer overflow
// DEFENSIVE BITWISE RULE: Always validate inputs using subtraction BEFORE executing addition.
// If packet_len is larger than MAX_ALLOWED_PACKET, reject immediately.
if (packet_len > MAX_ALLOWED_PACKET) {
free(heap_block);
close(acceptFd);
return;
}
// SECURE STEP 4: Prevent Integer Overflow
// Since packet_len is proven to be <= 8190, this addition is mathematically guaranteed never to overflow
alloc_size = (size_t)packet_len + 2;
// Allocate heap memory based on the verified safe size and perform NULL verification
heap_block->buffer = (char*)malloc(alloc_size);
if (heap_block->buffer == NULL) {
free(heap_block);
close(acceptFd);
return;
}
// Assign the trusted safe handler callback function pointer
heap_block->error_handler = safe_handler;
// SECURE STEP 5: Safe Payload Ingestion
// Since packet_len is strictly smaller than alloc_size, a heap buffer overflow is physically impossible
int received = recv(acceptFd, heap_block->buffer, packet_len, 0);
if (received < 0) {
printf("DEBUG: Error occurred while receiving packet payload\n");
}
// Verify if the function pointer address remains pristine and uncorrupted after packet read
printf("DEBUG: After recv -> heap_block->error_handler = %p\n", heap_block->error_handler);
// Execute the verified function pointer securely
heap_block->error_handler();
// SECURE STEP 6: Mandatory Resource Cleanup
// Deallocate memory and close descriptors to prevent memory leaks and file descriptor exhaustion (DoS)
free(heap_block->buffer);
free(heap_block);
close(acceptFd);
}
********* Another example explain *********
Binary Exploitation Analysis: From Memory Layout to Vulnerability Mechanics
This document compiles the architectural memory layouts, assembly code paths,
and logical vulnerabilities associated with low-level stack buffer overflows and
integer overflow conditions.
### 【 Text Segment (Executable Code Space) 】
#text
Memory Address Instructions
0x1000 <filter_and_spawn>: Perform security validation...
...
0x2005 ret <-- [Current RIP points here]
...
0x3000 <execv>: Execute external binary execution... (Hacker's target!)
...
0x4000 <main>: Normal execution return target (Abandoned)
Memory Address Data Content inside Slot
0x9010 [ 0x41414141] (Overwhelmed by hacker's junk payload string "AAAA")
0x9008 [ 0x3000 ] <-- [Current RSP points here] (Critical! Return address overwritten to 0x3000)
0x9000 [ 0x41414141] (Buffer capacity filled with injected junk "AAAA")
High Memory Address
+-----------------------------------------------------+
| 0x9008 | [ 0x4000 ] -> Normal return address (Intended return path to main) |
+-----------------------------------------------------+
| 0x9000 | buffer[60-63] | \
+--------+--------------------------------------------+ \
| 0x8FFC | buffer[56-59] | \
| ... | ... | > Total 64-byte continuous buffer allocation
| 0x8FC4 | buffer[4-7] | / (RSP currently references 0x8FBC)
+--------+--------------------------------------------+ /
| 0x8FBC | buffer[0-3] <-- Buffer starting base boundary | /
+-----------------------------------------------------+
High Memory Address
+-----------------------------------------------------+
| 0x9008 | [ 0x3000 ] <-- Overwritten with malicious execv address via network stream!
+-----------------------------------------------------+
| 0x9000 | [ AAAA ] |
| ... | ... Completely flooded with 'A' padding ... |
| 0x8FBC | [ AAAA ] <-- Buffer starting base boundary |
+-----------------------------------------------------+
; --- Vulnerable Assembly Sequence ---
sub rsp, 64 ; Allocate 64 bytes on Stack (RSP = 0x8FBC, target ret slot resides at 0x9008)
mov rdi, [socket] ; Argument 1: Network socket file descriptor
lea rsi, [rsp] ; Argument 2: Memory address of buffer destination (0x8FBC)
mov rdx, 1024 ; Argument 3: Ingestion size limit (Fatal Error! Grants write capacity up to 0x93BC)
call recv ; Fire recv routine; memory boundaries broken beyond 0x9008
process_nas_packet:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp ; Allocate 16 bytes for local structural variables on the Stack
; ----------------------------------------------------
; Step 1: Read size header via recv(socket, &packet_len, 2, 0);
; ----------------------------------------------------
; RDI register is pre-populated with active socket descriptor by calling context
leaq -2(%rbp), %rsi ; Argument 2: Memory pointer reference to &packet_len
movq $2, %rdx ; Argument 3: Extract exactly 2 bytes from stream
movl $0, %rcx ; Argument 4: network options flag = 0
call recv ; Invoke standard library execution for recv
; ----------------------------------------------------
; Step 2: Validate boundary - Bypassed via type confusion / signedness optimization flaws
; ----------------------------------------------------
movzwl -2(%rbp), %eax ; EAX = packet_len (Hacker transmits malicious value 0xFFFF)
; If compiler optimization rules process packet_len as an explicitly signed int16_t element:
; 0xFFFF maps identically to a numerical representation of "-1"
cmpw $100, %ax ; Execute comparison: -1 against 100
jg .L_RETURN ; jg (Jump if Greater) evaluated conditionally: -1 is not greater than 100!
; Security validation boundary successfully bypassed! (Pass)
; ----------------------------------------------------
; Step 3: Compute allocation parameter: alloc_size = packet_len + 2; (Core Exploit Vulnerability)
; ----------------------------------------------------
movzwl -2(%rbp), %eax ; AX = 0xFFFF (65535)
addw $2, %ax ; Compute addition: AX = AX + 2
; Mathematical limit: 0xFFFF + 2 = 0x10001
; Because AX register constraints restrict width to 16 bits, the carry bit '1' is dropped
; The AX register truncates to 0x0001 (1) !!
movw %ax, -4(%rbp) ; System writes out alloc_size = 1
; ----------------------------------------------------
; Step 4: Instantiation of tracking buffer: char *buffer = malloc(alloc_size);
; ----------------------------------------------------
movzwl -4(%rbp), %eax ; EAX = 1 (Current alloc_size)
movq %rax, %rdi ; Argument 1: rdi = 1 (Request malloc engine to instantiate 1 byte allocation)
call malloc
movq %rax, -16(%rbp) ; buffer = Destination pointer returned by allocator (1-byte tracking footprint)
; ----------------------------------------------------
; Step 5: Payload ingestion: recv(socket, buffer, packet_len, 0); (Physical Memory Destruction)
; ----------------------------------------------------
movq -16(%rbp), %rsi ; Argument 2: Destination target pointer (points to the single byte space)
movzwl -2(%rbp), %edx ; Argument 3: Target stream processing packet_len = 0xFFFF (65535)
movl $0, %rcx ; Argument 4: network options flag = 0
call recv ; Fire payload ingestion!
; The recv routine obeys the OS kernel command, fetching 65535 bytes from the active network stream.
; It continuously pushes data into the memory pool starting at rsi.
; Because only 1 byte was allocated, the subsequent 65534 bytes overwrite sequential structures
; (Heap headers or Stack return slots), completely destroying tracking metadata and hijacking execution targets to execv!
.L_RETURN:
leave
ret
沒有留言:
張貼留言