Posts in 2020 mar

React .Net Core 3 Search Bar - lessons learned

[link to proj]( Finding a search bar in react is easy. Finding a .net project is easy too. The interesting part about this project is bridging these two technologies together. There are less materials out there about the intersection of two technologies, oftentimes. When one asks on Discord about a specific language (that is, under the right server & channel), it's usually pretty easy to get a solid response. In this case, however, it's harder. Folks would flat out tell ya they don't know either. But if you keep digging and thinking about different solutions, you get more familiar with the tech stack and find others' advises useful in the end.


[link]( ``` 0 - ssh, cat pretty standard ssh: ssh -p 2220 the password is on desktop/readme: cat readme 1 - better cat this level introduces a standard theme to all bandit levels: if it doesn't work, tweak it until it does: cat ./- 2 - even better cat modern linux systems auto-completes the escape character (\) for spaces in file name, making this level easy: cat spaces\ in\ this\ filename 3 - hidden file an easy google lookup should tell ya that a hidden file starts with a dot: bandit3@bandit:~$ ls inhere/ -a . .. .hidden bandit3@bandit:~$ cat inhere/.hidden pIwrPrtPN36QITSp3EQaw936yaFoFgAB 4 - file type this is when we need to start to rtfm: bandit4@bandit:~$ file inhere/* inhere/-file00: data inhere/-file01: data inhere/-file02: data inhere/-file03: data inhere/-file04: data inhere/-file05: data inhere/-file06: data inhere/-file07: ASCII text inhere/-file08: data inhere/-file09: data bandit4@bandit:~$ cat inhere/-file07 koReBOKuIDDepwhWk7jZC0RTdopnAYKh 5 - much better find there are lots of tricks to an instruction like find, here's my answer: find inhere/*/.* -size 1033c \! -executable -readable \! -path "*/../*" \! -path "*/./*" 6 - find then cat there's a neat one-liner for this: cat $(find / -user bandit7 -group bandit6 -size 33c 2>/dev/null) 7 - grep pretty standard: bandit7@bandit:~$ ls data.txt bandit7@bandit:~$ man grep bandit7@bandit:~$ grep millionth data.txt millionth cvX2JJa4CFALtqS87jk27qwqGhBM9plV 8 - sort, uniq, grep, pipe after some trial and errors, I realized that uniq only works with sort. another thing to notice is grep can find the line with frequency 1 after uniq. pipe, the most powerful tool in bash is introduced: bandit8@bandit:~$ sort data.txt | uniq -c | grep '1 ' 1 UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR 9 - strings, grep, pipe pretty standard after level 8: bandit9@bandit:~$ man strings bandit9@bandit:~$ strings data.txt | grep === 2========== the ========== password ========== isa ========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk 10 - base64 base64 is an encoding for files, and base64 command in bash can help encoding/decoding with the format: bandit10@bandit:~$ man base64 bandit10@bandit:~$ du data.txt 4 data.txt bandit10@bandit:~$ base64 -d data.txt The password is IFukwKGsFW8MOq3IRFqrxE1hxTNEbUPR 11 - rot13 i used python for this one: bandit11@bandit:~$ chmod 775 /tmp/mikey2521/ bandit11@bandit:~$ python3 /tmp/mikey2521/ < data.txt The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu bandit11@bandit:~$ cat /tmp/mikey2521/ #python3 cipher=input() plain='' for c in cipher: d=ord(c) if c.islower(): d=(d-ord('a')+13)%26+ord('a') elif c.isupper(): d=(d-ord('A')+13)%26+ord('A') plain+=chr(d) print(plain) 12 - file, various compression commands first move data.txt to your directory in /tmp/: mkdir /tmp/your-dir mv data.txt /tmp/your-dir then go to your directory and revert the hexdump: cd /tmp/your-dir xxd -r data.txt > reverted upon using file on reverted, we find that it's a gzip compressed file named 'data2.bin': bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted reverted: gzip compressed data, was "data2.bin", last modified: Tue Oct 16 12:00:23 2018, max compression, from Unix if only gunzip is used, even with the original name of data.bin, the following error occurs: bandit12@bandit:/tmp/mikey2521/lvl12$ gunzip reverted gzip: reverted: unknown suffix -- ignored after some search online, i realized that a .Z suffix is needed: mv reverted reverted.Z gunzip reverted.Z this time the compression seems to be bzip2: bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted reverted: bzip2 compressed data, block size = 900k and it went nicely, giving another gzipped file: bandit12@bandit:/tmp/mikey2521/lvl12$ bunzip2 reverted bunzip2: Can't guess original name for reverted -- using reverted.out bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted.out reverted.out: gzip compressed data, was "data4.bin", last modified: Tue Oct 16 12:00:23 2018, max compression, from Unix trying naive gunzip yields the same error before, so change the suffix to .Z one more time and decompress: bandit12@bandit:/tmp/mikey2521/lvl12$ mv reverted.out reverted.Z bandit12@bandit:/tmp/mikey2521/lvl12$ gunzip reverted.Z then use tar to decompress: tar xf reverted upon yielding data5.bin and finding it a tar archive again, produce data6.bin: tar xf data5.bin data6.bin is another bzipped file, so use bunzip: bunzip data6.bin data6.bin.out is another tar archive which produces data8.bin, a gzipped file: tar xf data6.bin.out mv data8.bin data8.Z gunzip data8.Z this finally gives the password file, data8: bandit12@bandit:/tmp/mikey2521/lvl12$ file data8 data8: ASCII text bandit12@bandit:/tmp/mikey2521/lvl12$ cat data8 The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL 14 - sshkey copy the sshkey to a local file of random name don't forget to change permission of the file to 700 use -i flag in ssh to remote into level 14: chmod 700 lvl14key ssh -p 2220 -i lvl14key 15 - nc pretty straightforward if you know where bandit14's password is: cat /etc/bandit_pass/bandit14 | nc localhost 30000 16 - yet another port scan first, use nmap to detect open ports: nmap localhost -p 31000-32000 then, use openssl and s_client to talk to the server. after a failure, the server on port 31790 returns a RSA key. use that key to connect to the next level (just like an earlier level): openssl s_client -connect localhost:31790 ssh -p 2220 -i lvl17key 17 - diff standard solution: diff passwords.old i prefer vimdiff vimdiff passwords.old 18 - malicious bashrc, command over ssh after a little trial and error, here's the solution: ssh -p 2220 "cat ~/readme" 19 - setuid binary, priviledge escalation the instruction is not so clear for this one and it took some unnecessary time for me to guess the straightforward solution: ./bandit20-do cat /etc/bandit_pass/bandit20 20 - netcat, tcp the description took me quite a while to figure out what to do. but basically you first open one window and write: nc -lp 31791 < /etc/bandit_pass/bandit20 then another window and write: ./suconnect 31791 the logic is that the a port on the localhost (default for nc) will have the old password on it. when suconnect reaches it, suconnect sends the new password into the port and the -l flag ensures we get the password. 21 - cron cron runs scheduled tasks bandit22's cronjob is a shell script that enables me to read its password, its time is set to every minute, so i can just read the password: cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv 22 - more cron, bash this takes some reverse engineering. the password is hidden inside tmp folder, which i cannot read. however, i can read all files' content in /tmp. the password is hidden because it uses a processed md5sum based on the username. but this is deterministic so it's easy to reconstruct. cat /tmp/$mytarget where mytarget is: echo I am user bandit23 | md5sum | cut -d ' ' -f 1 23 - bash, simple exploit the thought is along the lines of level 22. you need to identify a weakness in the victim script and use it to your advantage. it is more straightforward in a way once you understand what the bash script is doing. the script is simply executing and removing all the files in /var/spoof/bandit24. so just sneak a file in there that leaks the password. notice the password needs to be written to a place that has write permission and the file needs to have execute permission: mkdir /tmp/oh_long_johnson chmod 777 /tmp/oh_long_johnson vim /var/spoof/bandit24/ (inside vim) #!/bin/sh cat /etc/bandit_pass/bandit24 >> /tmp/oh_long_johnson/b24.txt (outside vim) chmod 777 /var/spoof/bandit24/ #wait a minute cat /tmp/oh_long_johnson/b24.txt 24 - bash, burte force this one i actually used python3. since it's slower than bash, i need to cut the guess in half (0-5,000, 5,000-10,000) and here's the code (named pswd='UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ ' with open('out.txt','w') as f: for i in range(5000,10000): f.write(pswd+str(i).zfill(4)+'\n') use this to produce a list of guesses and use an earlier level to get the uniqe lines that contains the password (since thankfully all the error messages are the same): python3 nc localhost 30002 < out.txt > out2.txt sort out2.txt | uniq -c | grep '1 ' 25 & 26 - more, set shell these two levels are pretty hard. i did not do this on my own. first, we need to notice in level 25 what level 26 is doing: cat /etc/passwd | grep bandit26 this is a common exploit for earlier linux/unix systems, but it's hard for newcomers to learn about this at first. however, once this is done, one can follow a thread of information until one gets the private ssh key for level 26, as well as knowing what level 26 is doing: 1. switching terminal emulator to linux 2. call more on text.txt 3. exit hmm... it seems a terminal emulator is pretty unhackable at the moment, when we can't influence it by any commands in ssh. the exit throws us right back to our local machine. the only point of weakness left is the 'opposite of less', more. more is only triggered when there's more to the document than the screen. so with a six line document, i had to squash the terminal window to less than six lines tall... but even then i can't do much within more. it's not like vim, where there's a million things i can do to hack the 'outside world'. it's time to rtfm. after a rather painful search in more's man page, a command finally brings a hope: v. v calls the text editor that starts with v, vim, and opens a path to victory. once vim is opened, there are usually many ways to call external shell commands and do almost everything in vim. but in this case i could only set the shell by, well, 'set shell=/bin/bash'. then it's just a priviledge escalation (setuid) and we're onto a couple of easy levels using git. 27 - git clone just clone it and cat the readme file. 28 - git log, checkout the cloned repo has no real password. so a natural thing to think about is log and previous versions. from log's comments i was able to recover the password from a previous commit. pretty standard. 29 - git branch first use: git show-branch -a then: git checkout origin/dev cat 30 - git show git clone... git tag git show secret 31 - git add, git commit, git push pretty standard 32 - redirection >> is probably redirecting, and converts everything to uppercase in the wrapper. the correct command is $0 to get it redirected to bash ```

LC weekly contest 178

rank: 1036 / 9210 [P1]( Too easy, brute force. ```python class Solution: def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]: r=[] for n in nums: cur=0 for m in nums: if m<n: cur+=1 r+=cur, return r ``` [P2]( use numerical method to enforce written rules. ```python class Solution: def rankTeams(self, votes: List[str]) -> str: r=1001 d={s:0 for s in votes[0]} for v in votes: p=1 for c in v[::-1]: d[c]+=p p*=r S=sorted(d.items(),key=lambda y:y[1]*257-ord(y[0])) x=[s[0] for s in S][::-1] return ''.join(x) ``` [P3]( In order to achieve O(list*tree) complexity, need to think about the problem this way: as we go through the list, there will be less and less nodes that satisfies the requirement so we can get rid of them. The rest is wise choice of data structures. Note the following solution (during contest) can be speeded up using a pre-computed depth value that filters all nodes that are not deep enough. But that won't be an asymptotic improvement. Also there are cleaner solutions written for this. ```python # Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # = None # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSubPath(self, head: ListNode, root: TreeNode) -> bool: if not head: return True D=dict() self.tag=0 def trav(node): if node: D[self.tag]=node self.tag+=1 node.t=self.tag trav(node.left) trav(node.right) trav(root) ll=head while ll: E=dict() if not D: return False for k,v in D.items(): if v.val==ll.val: if v.left: lk=v.left.t E[lk]=v.left if v.right: rk=v.right.t E[rk]=v.right D=E if ll: print(ll.val) return not ll ``` [P4]( I tried dp and binary search but did not think of any good idea. Turns out it's a bfs/Dijkstra kinda problem.

lc 68 - text justification

this is one of those problems that gets impatient people. it is hard to get everything right without a few trials. for me, i had 4. as you can see the code is quite lengthy. ```python from math import ceil class Solution: def fullJustify(self, words: List[str], maxWidth: int) -> List[str]: o=[''] for w in words: if len(w)==maxWidth: if not o[-1]: o[-1]=w o+=[''] else: o+=[w,''] elif len(w)+1+len(o[-1])>maxWidth: #bag is the "bag" of words (in order, lacks a better name) #in the last line line, bag='', o[-1].split() if len(bag)==1: #pad single-word line o[-1]+=' '*(maxWidth-len(o[-1])) else: sl=len(bag)-1 S=[1]*sl for i in range(maxWidth-len(o[-1])): S[i%sl]+=1 for i,b in enumerate(bag): line+=b+' '*S[i] if i<sl else b o[-1]=line o+=[w] else: o[-1]+=' '+w if o[-1] else w #pad rest of line o[-1]+=' '*(maxWidth-len(o[-1])) if len(set(o[-1]))==1 and ' ' in set(o[-1]): o=o[:-1] for i in range(len(o)): o[i]+=' '*(maxWidth-len(o[i])) return o if words else [] ```