I have started playing around in https://www.hackthebox.com platform and I’ll use this article to save all the knowledge I’ve got regarding pentesting and certain programming languages.

This article describe some features of programming languages that if used wrong, they can be attack vectors for applications. It’s not that the language is unsecure, but the features can be misused very easily.

Programming languages

  1. PHP
  2. C

PHP

Type juggling

Due to the nature of PHP we can abuse the type jungling feature.

The following condition will be true and print the message.

$example_int = 7
$example_str = 7
if ($example_int == $example_str) {
   echo("PHP can compare ints and strings.")
}

So, an if with == will not check the types. Only === check the types. Internally php select statement uses == comparisson, therefore is vulnerable to this kind of vulnerability. See https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09

So, if you spot a switch statement that checks a user provided string, just change the string value to true.

strcmp

You can also check if the page is using php to abuse the strcmp function.

if(strcmp($PASSWORD, $_GET['password']) == 0){
        $success = true;
}

Thanks to the type juggling describe above, if strcmp returns NULL the condition will be true. We can force this by passing the password field as an array:

http://yrmyzscnvh.abctf.xyz/web6/?password[]=%22%22

Example: https://www.doyler.net/security-not-included/bypassing-php-strcmp-abctf2016

C

union

A union type in C lang is a special type that allows the developer to reuse a memory position to store multiple types of data.

#include <stdio.h>
#include <string.h>
 
union Data {
   int i;
   float f;
   char str[20];
};
 
int main( ) {

   union Data data;        

   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");

   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);

   return 0;
}

Outputs:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

If the developer rely on this union to hide a secret and let the user access to it, the user can change the value of the union by writing a different type that will be converted to the proper type when checking the secret.

Example:

static union {
    unsigned long long integer;
    char string[8];
} DataStore;

void get_flag() {
    if (DataStore.integer == 13371337) {
        system("cat flag.txt");
        exit(0);
    } else {
        puts("\nSorry, this will not work!");
    }
}
void set_field(field_t f) {
    char buf[32] = {0};
    printf("\nMaybe try a ritual?\n\n>> ");
    fgets(buf, sizeof(buf), stdin);
    switch (f) {
    case INTEGER:
        sscanf(buf, "%llu", &DataStore.integer);
        if (DataStore.integer == 13371337) {
            puts("\nWhat's this nonsense?!");
            exit(-1);
        }
        break;
    case STRING:
        memcpy(DataStore.string, buf, sizeof(DataStore.string));
        break;
    }
}

It turns out, the user can write to both fields in the union. However, if we set the magic number to get the secret, the app will exit. However, we can set in the string the byte value of the integer field:

r.sendline(p64(13371337))

In the example we use python pwntools library to generate the byte value (in 64 bytes) of the magic number.