I hope this is not off-topic here. This is the background:
My friend and I are trying to solve this online puzzle where you basically have to enter a 16 digit combination; if wrong, the site'll display "incorrect" and, if right, some other message we don't know about. We have the first eight numbers so we figured it would be feasible attempting to brute-force it using curl and saving to output to check.
We've implemented it like this:
curl http://www.game.com/checkCombo.php?num1=[0-9]&num2=[0-9]...&num8=[0-9] >> output.txt
As you can see, we're basically running through all possible combinations and appending each individual output to the "output.txt" file.
The way we check whether we've gotten the right combination, since we don't know what it'll say then, is by searching the number of "incorrects"; if when we open the file we've gone through 1000 combinations and there are 1000 matches for "incorrect" then we know we haven't hit the right one yet. If when we open the file we've gone through 2000 combos and there are only 1999 matches for "incorrect", we know we've hit the right combo and we just search for it.
However, since we're saving 10^8=100,000,000 individual outputs, we're running out of space on the computer.
We tried pausing the cURL process with "ctrl+z" and checking the file to see whether we've hit the right combo. If not, we clear the "output.txt" file, save it, and resume the cURL process with "fg %#".
The problem is that when we resume cURL, after we've cleared the text file, the file remains empty: the output of cURL won't save any more onto the file.
I'd like to know whether there's a way of pausing cURL to check the file, clearing the file, and resuming curl while continuing to save the remaining outputs.
If you have other ideas on how we might go about the combination, I'd also appreciate hearing about them. Thank you.
A simplified case will show different things to get started. Start testing without curl until you have a working solution.
I have written a funtction checkcombo that needs 3 parameters and has a hidden solution:
checkcombo () {
digit=$1$2$3
if [[ $digit = 412 ]]; then
echo "How did you find me?"
else
echo incorrect
fi
}
Try this function with
checkcombo 4 1 0
checkcombo 4 1 1
checkcombo 4 1 2
Nice, now we want bruteforce. Perhaps the best solution is one loop until 999 and split each number in 3 digits, but I want to show the nested loops.
for i in {0..9}; do
for i2 in {0..9}; do
for i3 in {0..9}; do
checkcombo $i $i2 $i3 | grep -q "incorrect" || { echo The answer is $i $i2 $i3 && break 3; }
done
done
done
The line with checkcombo can be hard to read. It is a short way of saying
if [ $(checkcombo $i $i2 $i3 | grep "incorrect" | wc -l) -eq 0 ]; then
echo "The answer is $i $i2 $i3"
# and stop testing with break 3
fi
Related
I am using a curl command to get json data from an application called "Jira".
Stupidly (in my view), you cannot use the api to return more than 50 values at a time.
The only choice is to do it in multiple commands and they call this "pagination". It is not possible to get more than 50 results, no matter the command.
This is the command here:
curl -i -X GET 'https://account_name.atlassian.net/rest/api/3/project/search?jql=ORDER%20BY%20Created&maxResults=50&startAt=100' --user 'scouse_bob#mycompany.com:<sec_token_deets>'
This is the key piece of what I am trying to work into a loop to avoid having to do this manually each time:
startAt=100
My goal is to "somehow" have this loop in blocks of fifty, so, startAt=50 then startAt=100, startAt=150 etc and append the entire output to a file until the figure 650 is reached and / or there is no further output available.
I have played around with a command like this:
#!/bin/ksh
i=1
while [[ $i -lt 1000 ]] ; do
curl -i -X GET 'https://account_name.atlassian.net/rest/api/3/project/search?jql=ORDER%20BY%20Created&maxResults=50&startAt=100' --user 'scouse_bob#mycompany.com:<sec_token_deets>'
echo "$i"
(( i += 1 ))
done
Which does not really get me far as although it will loop, I am uncertain as to how to apply the variable.
Help appreciated.
My goal is to "somehow" have this loop in blocks of fifty, so, startAt=50 then startAt=100, startAt=150 etc and append the entire output to a file until the figure 650 is reached and / or there is no further output available.
The former is easy:
i=0
while [[ $i -lt 650 ]]; do
# if you meant until 650 inclusive, change to -le 650 or -lt 700
curl "https://host/path?blah&startAt=$i"
# pipe to/through some processing if desired
# note URL is in " so $i is expanded but
# other special chars like & don't screw up parsing
# also -X GET is the default (without -d or similar) and can be omitted
(( i+=50 ))
done
The latter depends on just what 'no further output available' looks like. I'd expect you probably don't get an HTTP error, but either a contenttype indicating error or a JSON containing either an end or error indication or a no-data indication. How to recognize this depends on what you get, and I don't know this API. I'll guess you probably want something more or less like:
curl ... >tmpfile
if jq -e '.eof==true' tmpfile; then break; else cat/whatever tmpfile; fi
# or
if jq -e '.data|length==0' tmpfile; then break; else cat/whatever tmpfile; fi
where tmpfile is some suitable filename that won't conflict with your other files; the most general way is to use $(mktemp) (saved in a variable). Or instead of a file put the data in a variable var=$(curl ...) and then use <<<$var as input to anything that reads stdin.
EDIT: I meant to make this CW to make it easier for anyone to add/fix the API specifics, but forgot; instead I encourage anyone who knows to edit.
You may want to stop when you get partial output i.e. if you ask for 50 and get 37, it may mean there is no more after those 37 and you don't need to try the next batch. Again this depends on the API which I don't know.
I know this question has been answered so many times. However, I still have some points need to be clarified. First let me paste my code snippet:
1 #!/bin/bash
2 declare -a test
3 declare -i counter
4
5 while read x;
6 do
7 test[counter]=$x
9 ((counter++))
10 done < reg.txt
11 echo "---------------------"
12 echo ${test[0]}
13 echo ${test[1]}
And the data in reg.txt is
1.1.1.1
2.2.5.6
45.25.12.45
1.1.2.3
1.1.3.4
I know that to put data in array test properly, I have to use '<' to turn file "reg.txt" into input data. However, how am I supposed to pick out ip address contains "1.1".
At line 10, I tried different things such as:
done < reg.txt|grep "1.1" #Using this way makes the 'test' array empty.
Or this:
done < <(reg.txt | grep "1.1")
The grammar is incorrect. (A lot of people suggest this and I don't know why).
In summary, I mean, is there a way to re-construct file before being read by while loop?
Using this syntax:
done < reg.txt|grep "1.1"
doesn't do what you want it to do; instead, it applies the grep command to the output of the while loop.
The test array is does get populated with 5 values, but those values aren't remembered after the while loop completes - as explained in the answers to this question: Modifying a variable inside while loop is not remembered
What you're looking for is this:
done < <(cat reg.txt | grep "1\.1")
Note that the part within the parenthesis is a pipeline, and it needs to be a valid bash command. (You were missing the "cat" command.) You can test that part separately and verify that it selects the input data that you want.
I have having an interesting issue that I can't seem to figure out.
I have a basic script that pulls configuration information and just redirects it to a file:
cat /etc/something > 1
cat /etc/something-else > 2
As soon as my data gather is finished, I run a "parser" that presents info about the check:
#58
id="RHEL-06-000001"
ruleid="The system must require passwords to contain at least one special character."
if grep -G [a-z] 1; then
ocredit=`cat 1 | grep -v "^#" | awk '{print $2}'`
if [ "$ocredit" -le -1 ]; then
result="Not A Finding"
todo="None"
else
result="Open"
todo="The current value is $ocredit. This is less than the minimum requirement of - 1."
fi
else
result="Open"
todo="The option is not configured"
fi
echo "$id, $ruleid, $result, $todo" >> Findings.csv
#59
id="RHEL-06-000002"
ruleid="The system must require passwords to contain at least one lowercase alphabetic character."
if grep -G [a-z] 2; then
lcredit=`cat 2 | awk -F"=" '{print $2}'`
if [ "$lcredit" -le -1 ]; then
result="Not A Finding"
todo="None"
else
result="Open"
todo="The current value is $lcredit. This is less than the minimum requirement of -1."
fi
else
result="Open"
todo="The system is not configured to require at least one lowercase alphabetical charatcer in passwords."
echo "$id, $ruleid, $result, $todo" >> Findings.csv
Or something remotely close to that.
I have roughly 250 of these checks happening but my code is runs the first 58 and then stops and no longer redirects content to the checks.csv.
I do get an error after the script finishes prematurely, stating
./checker.sh: line 2898: syntax error: unexpected end of file
which is the end of my file, but I can't seem to figure out how it is escaping to that point in the script.
The kicker, this all worked until about a half hour ago and it has be stumped.
Can you help me out?
You seem to be missing the fi after your second-last line:
else
result="Open"
todo="The system is not configured to require at least one lowercase alphabetical charatcer in passwords."
## HERE ##
echo "$id, $ruleid, $result, $todo" >> Findings.csv
That could potentially cause problems for the bash parser when encountered, causing an EOF error when bash tries to find the missing fi.
That probably means you've got an unclosed if statement or similar. Bash reads simple commands on-demand, but when it comes upon a complex statement like that, it wants to read the whole if statement and its contents. If it then comes upon an EOF while still trying to read to the end of it, it will give you that error.
Currently I'm creating a little script in BASH that will ask the user to fill in a new IP-address, subnet and gateway. That input goes to a file which will be writen to /etc/network/interface..
I got the script working, but it isn't bullet proof.
When the user input, is not a number but an alphabetic character, It returns and the user needs to fill again a number.
When the user still uses a alphabetic character, the script continues, even though giving a error.
My code:
echo "Fill in your IP"
read NEW_IP
oldIFS=$IFS
IFS=.
set -- $NEW_IP
while [ $# -ne "4" ]; do
echo "Must have 4 parts"
read NEW_IP
set -- $NEW_IP
done
for oct in $1 $2 $3 $4; do
echo $oct | egrep "^[0-9]+$" >/dev/null 2>&1
while [ "$?" -ne "0" ]; do
echo "$oct is not numeric. fill your IP in the correct format;"
read NEW_IP
set -- $NEW_IP
done
I'm new with bash, above I didn't make it by my self. I've found this script on the internet. The while and do, I made that by my self as a loop.
Everytime the user fills in a wrong number It must return untill the user filled in a correct format.
The real problem lies at the second half of the code. When I fill in a wrong IP like 10.10.10.a, I get the error like I want and I have to fill in for the second time my IP.
When I type 10.41.12.r, an error occured but this time, not complaining about the r at the end, but still complaining about the a which I inserted at the first. 10.41.12 will be checkt, but that last character is different.
I can imagine that everything will be stored in memory, but how do I clear that?
unset or $oct=
won't work
Hope that someone can help me with this. It's my first time programming, and this is giving me a headache
thanks.
Dave
for does not evaluate the condition several times. It just runs 4 times, setting $oct to $1 .. $4. If you try several times, your input will be accepted, even if not numeric. Moreover, you should check "Must have 4 parts" again after getting the input in the loop.
BTW, you should check that each $oct <= 255.
Duplicated code is often bad. Better read the input at one place and go through the same tests everytime.
prompt="Fill in your IP"
while
echo $prompt
read NEW_IP
IFS=.
set -- $NEW_IP
IFS=
if [ $# -ne 4 ]
then
prompt="Must have 4 parts"
continue
fi
for oct
do if [[ ! "$oct" =~ ^[0-9]+$ ]]
then
prompt="$oct is not numeric. fill your IP in the correct format;"
continue 2
fi
# You might add more checks here.
done
do break
done
First off, I appreciate any and all help in answering this question.
I have a command in a bash script that will output the following:
255 254 253 252 ... 7 6 5 4 3 2 1
It is a specific list of numbers, beginning with the largest (which is what I would like), then going to the smallest. The dataset is space-delimited. The output above (except including all numbers), is what you would see if you ran this command in the terminal on a linux machine, or through a bash script.
I have configured my apache2 server to allow for cgi/bash through the cgi-bin directory. When I run this command in a bash file from the web, I get the expected output.
What I'm looking for is for a way to be able to put these numbers each as a separate entry in a drop-down box for selection, meaning the user can select one point of data (254, for example) from the drop down menu.
I'm not sure what I'm doing with this, so any help would be appreciated. I'm not sure if I need to convert the data into an array, or what. The drop down menu can be on the same page of the bash script, but wherever it is, it has to update it's list of numbers from the command every time it is run.
Thank you for your help.
I've always found this site useful when fiddling with shell scripts: http://tldp.org/LDP/abs/html/
you'll have to get your output into an array using some sort of string manipulation using the spaces as delimiters, then loop over that to build some html output - so the return value will basically just output your select box on the page where you execute your cgi/bash script.
-sean
Repeating the answer (since the original question was marked as duplicate):
you can write a bash for loop to do everything. This just prints out the elements:
for i in `seq 1 "${#x[*]}"`; do
echo "|${x[i]} |"
done
To get the alignment correct, you need to figure out the max length (one loop) and then print out the terms:
# w will be the length
w=0
for i in `seq 1 "${#x[*]}"`; do
if [ $w -lt ${#x[$i]} ]; then w=${#x[$i]}; fi
done
for i in `seq 1 $((w+2))`; do printf "%s" "-"; done
printf "\n"
for i in `seq 1 "${#x[*]}"`; do
printf "|%-$ws |\n" ${#x[$i]}
done
for i in `seq 1 $((w+2))`; do printf "%s" "-"; done
printf "\n"