Similar to how you can use pack's:
N An unsigned long (32-bit) in "network" (big-endian) order.
Is there any method for packing a 64-bit integer in "network" (big-endian) order in Perl?
If your system supports the Q pack format, you can use Q> to get big-endian (since Perl 5.9.2):
% perl -e 'print pack("Q>", 1)' | hexdump -C
00000000 00 00 00 00 00 00 00 01 |........|
Related
I have a small socket filter type eBPF program, where I'm trying to print a protocol value read from __sk_buff context:
struct bpf_insn prog[] = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, offsetof(struct __sk_buff, protocol)),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -4),
BPF_MOV64_IMM(BPF_REG_2, 4),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_trace_printk),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};
...
I create a raw socket and bind it to the lo interface, then setsockopt(fd, SOL_SOCKET, SO_ATTACH_BPF, ...). It compiles and loads with no problems, however whenever I ping 127.0.0.1 I never see traces in the trace_pipe.
So, to make sure that it BPF_FUNC_trace_printk actually can work, I changed it so that it prints a static string on the stack, and it does print on every packet hitting the loopback.
What am I doing wrong?
Read the friendly manual :)
I don't believe you are calling the bpf_trace_printk() helper correctly (BPF_FUNC_trace_prink is just an integer, by the way). Its signature, commented in the kernel UAPI header bpf.h or in the bpf-helpers man page, is as follows:
long bpf_trace_printk(const char *fmt, u32 fmt_size, ...);
This means that the first argument must be a constant, null-terminated format string, not an integer like you do.
What does clang do?
I understand you are attaching your eBPF programs to sockets and cannot compile the whole program from C. However, why not compile that specific part as a generic networking eBPF program to see what the bytecode should look like? Let's write the C code:
#include <linux/bpf.h>
static long (*bpf_trace_printk)(const char *fmt, __u32 fmt_size, ...) = (void *) BPF_FUNC_trace_printk;
int printk_proto(struct __sk_buff *skb) {
char fmt[] = "%d\n";
bpf_trace_printk(fmt, sizeof(fmt), skb->protocol);
return 0;
}
Compile to an object file. For the record this would not load, unless we provide both a valid licence string (because bpf_trace_prink() needs a GPL-compatible program) and a compatible program type at load time. But it does not matter in our case, we just want to look at the generated instructions.
$ clang -O2 -g -emit-llvm -c prink_protocol.c -o - | \
llc -march=bpf -mcpu=probe -filetype=obj -o prink_protocol.o
Dump the bytecode:
$ llvm-objdump -d prink_protocol.o
prink_protocol.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <printk_proto>:
0: b4 02 00 00 25 64 0a 00 w2 = 680997
1: 63 2a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r2
2: 61 13 10 00 00 00 00 00 r3 = *(u32 *)(r1 + 16)
3: bf a1 00 00 00 00 00 00 r1 = r10
4: 07 01 00 00 fc ff ff ff r1 += -4
5: b4 02 00 00 04 00 00 00 w2 = 4
6: 85 00 00 00 06 00 00 00 call 6
7: b4 00 00 00 00 00 00 00 w0 = 0
8: 95 00 00 00 00 00 00 00 exit
We can see that on the first two instructions, the program writes the format string (in little endian) onto the stack: 680997 is 0x000a6425, \0\nd%. r2 still contains the length for the format string. The protocol value is stored in r3, the third argument for the call to bpf_trace_prink().
In WinDbg I can search the memory for bytes using the s command, e.g.
s 0012ff40 L?2000 48 65 6c 6c 6f
Is there also a way to include unknown bytes in the search sequence, e.g.
s 0012ff40 L?2000 48 65 ?? ?? ?? 6c 6f
where ?? is a byte with an arbitrary value?
Idea
How about doing ((memory XOR 48 65 00 00 00 6c 6f) AND FF FF 00 00 00 FF FF) and compare that against 00 00 00 00 00 00 00? But I don't know how to do that in WinDbg either.
Am not sure if the search command supports wild card. But you can use .foreach command, to achieve what you want.
Here is a sample that i used to search a memory pattern such as ff ?? 00
.foreach (hit {s -[1]b 00007ffabc520000 L100 ff }) {db hit L3; s ${hit}+2 L1 00}
Here is a brief description of how it works :
NOTE - Open up the debugger help from windbg to get complete documentation. That is within Windbg, Help | Contents
{s -[1]b 00007ffabc520000 L100 ff }
Use -[1] flag with s, so that only the memory address is given as the output.
s ${hit}+2 L1 00
For each hit, pass that memory address to the next search command. Increase the memory by the number of bytes that you want to skip and mention the last part of search pattern.
db hit L3
From the memory that has the beginning of the patter, dump the entire length. This is just to confirm that we are getting the right results!
Hope this helps. In case you need further clarification, i can try to provide that as well.
We can use pykd to achieve this. Find the downloads linked from PyKD Wiki or PyKD Downloads. When using WinDbg Preview, copy the DLLs into
%LOCALAPPDATA%\DBG\EngineExtensions
for 64 bit or
%LOCALAPPDATA%\DBG\EngineExtensions32
for 32 Bit.
Since this is only the WinDbg extension, you also need the Python module as well:
pip install pykd
Use the power of Python to do what WinDbg can't do. Save the following script in a good place for WinDbg, i.e. in a short path without spaces.
from pykd import *
import sys
import re
import struct
if len(sys.argv)<4:
print("Wildcard search for memory")
print("Usage:", sys.argv[0], "<address> <length> <pattern> [-v]", sep=" ")
print(" <address>: Memory address where searching begins.")
print(" This can be a WinDbg expression like ntdll!NtCreateThreadEx.")
print(" <length> : Number of bytes that will be considered as the haystack.")
print(" <pattern>: Bytes that you're looking for. May contain ?? for unknown bytes.")
print(" [-v] : (optional) Verbose output")
print()
print("Examples:")
print(" ", sys.argv[0], "00770000 L50 01 02 03 ?? 05")
print(" will find 01 02 03 04 05 or 01 02 03 FF 05, if present in memory")
sys.exit(0)
verbose = False
if sys.argv[-1][0:2] == "-v":
verbose = True
if verbose:
for n in range(1, len(sys.argv)):
print(f"param {n}: " + sys.argv[n])
address = expr(sys.argv[1])
if verbose: print("Start address:", "0x{:08x}".format(address), sep=" ")
length = sys.argv[2]
length = length.replace("L?","") # consider large address range syntax
length = length.replace("L","") # consider address range syntax
length = expr(length)
if verbose: print("Length:", "0n"+str(length), "bytes", sep=" ")
regex = b""
for n in range(3, len(sys.argv) - 1 if verbose else 0):
if sys.argv[n] == "??":
regex += bytes(".", "ascii")
else:
char = struct.pack("B", expr(sys.argv[n]))
if char == b".":
regex += struct.pack("B", ord("\\"))
regex += char
if verbose: print("Regex:", regex, sep=" ")
memorycontent = loadBytes(address, length)
if verbose: print("Memory:", memorycontent, sep=" ")
result = re.search(regex, bytes(memorycontent))
print("Found:", ' '.join("0x{:02x}".format(x) for x in result.group(0)), "at address", "0x{:08x}".format(address+result.start()))
The script constructs a Regex for a Bytes object. It uses . for the wildcard and escapes literal . to \..
Let's prepare a proper sample in WinDbg:
0:006> .dvalloc 1000
Allocated 1000 bytes starting at 00900000
0:000> eu 0x00900000 "Test.with.regex"
0:000> db 0x00900000 L0n30
00900000 54 00 65 00 73 00 74 00-2e 00 77 00 69 00 74 00 T.e.s.t...w.i.t.
00900010 68 00 2e 00 72 00 65 00-67 00 65 00 78 00 h...r.e.g.e.x.
Load the PyKD extension, so we'll be able to run the script:
0:006> .load pykd
and run the script:
0:000> !py d:\debug\scripts\memwild.py 00900000 L10 2e ?? 77
Found: 0x2e 0x00 0x77 at address 0x00900008
If the range of the search is not insanely large you could copy/paste the hex dump into sublime text and just do a find with regex mode enabled. For example I was looking for (1200 < X < 2400)
add esp, X
ret
In sublime text I searched using the regex 81 c4 .. .. .. 00 c3 and found an address with instructions for
add esp,600h
ret
I am using the unpack function to convert the contents of a binary file to hexadecimal.
I am doing it as follows:
#! /usr/bin/perl
use strict;
use warnings;
my $input=$ARGV[0];
open(INPUT,'<',$input) || die("Couldn't open the file, $input with error: $!\n");
my $value=<INPUT>;
$value=unpack("H*",$value);
print $value,"\n";
This prints the contents of the binary input file as a hex string.
However, the issue is that, while parsing the contents of the binary file, if it comes across the byte 0xa (newline character), unpack function stops at that point.
As a result of this, I get the incomplete output in $value variable.
Few examples:
65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 BA DC 95 DC FE BD
FE FF FF FF 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00
All the content after the byte, 0xa is not parsed by unpack.
So, is there a way to use unpack for the complete binary file so that it does not stop parsing once it encounters a new line character?
Thanks.
What do you think
my $value = <INPUT>;
does? Read a line, which is to say read until 0A. Fix:
my $value;
{ local $/; $value = <INPUT>; }
Also, you want to add
binmode(INPUT);
after the open.
I got a small question.
Say I have the following code inside a console application :
printf("Enter name: ");
scanf("%s", &name);
I would like to exploit this vulnerability and enter the following shell code (MessageboxA):
6A 00 68 04 21 2F 01 68 0C 21 2F 01 6A 00 FF 15 B0 20 2F 01
How can I enter my shell code (Hex values) through the console ?
If I enter the input as is, it treats the numbers as chars and not as hex values.
Thanks a lot.
You could use as stdin a file with the desired content or use the echo command.
Suppose your shell code is AA BB CC DD (obviously this is not a valid shellcode):
echo -e "\xAA\xBB\xCC\xDD" | prog
How can I unpack a 4byte binary file, store like the following example,
to array or TEXT file ?
input file:
00000000 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 00 |................|
00000001 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 |................|
desired output file:
0,1,1,0,1,1,1,1
For now I'm using the following unpack code:
open(ERROR_ID_BIN, "<", "/error_id.bin") or die $!;
local $/;
my #err_values = unpack("V*", <ERROR_ID_BIN>);
close(ERROR_ID_BIN);
print "\n\n\n\n\t#err_values\n\n\n";
And my problem is that it flips the values and gives me that:
0,16777216,16777216,0,16777216,16777216,16777216,16777216
What should I do ?
V is little-endian (least significant byte first); try N for big-endian (most significant byte first).
From the pack documentation
N An unsigned long (32-bit) in
"network" (big-endian) order.
V An
unsigned short (32-bit) in "VAX"
(little-endian) order.
Don't you want 'N' to correct your endness ?